• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Czy program musi być liniowy?

Object Storage Arubacloud
+2 głosów
259 wizyt
pytanie zadane 5 stycznia 2016 w Algorytmy przez Sinnley Stary wyjadacz (12,810 p.)
Witam, nachodzi mnie pewne pytanie - czy program musi być liniowy?

Jestem na dosć początkującym poziomie nauki programowania, znam podstawy.

Dotychczas pisząc kod, zauważyłem, że nie mam pojęcia jak sprawić, aby program nie robił wszystkie pokolei.

Podam przykład, załóżmy, że piszę program który "wypisuje" nam płaszczyznę, na której leży kilka "klocków".

I chcę teraz te klocki "podniesć" o jedno miejsce w górę - jednoczesnie. Czy da się powiedzieć programowi, żeby wykonywał kilka czynnosci na raz?

Obecnie orientuję się jedynie w języku c++, głównie proceduralnym, aczkolwiek obiektowy poznaję na bierząco, więc cos tam już również wiem, nie mogę jednak znaleźć ani wymyslić nigdzie odpowiedzi na to pytanie.

3 odpowiedzi

+9 głosów
odpowiedź 5 stycznia 2016 przez Sebastian Fojcik Nałogowiec (43,040 p.)
wybrane 6 stycznia 2016 przez Sinnley
 
Najlepsza

Musisz uświadomić sobie przykrą prawdę:

Praktycznie nic w komputerze nie może zostać wykonane jednocześnie.

Jak oglądasz film na YT i "jednocześnie" rozmawiasz z kimś na Skype, to nie oznacza, że oba programy działają w tym samym czasie. Tobie się może wydawać, że tak jest. W rzeczywistości system przekazuje określoną ilość cykli procesora na dany proces jednak dzieje się to tak szybko, że sprawia to wrażenie, że programy działają jednocześnie.

Wracając do Twojego problemu z rysowaniem. Nie da się na raz podnieść wszystkich klocków, ale można to znacząco przyspieszyć. Możesz przykładowo napisać pętlę wypisującą duży zbiór znaków:

for( int i = 0; i < 15; i++ )
	cout << "########################################" << endl;

Wypisuje ona 15 linijek po 40 znaków '#' w każdej. I teraz zauważ, że pętla w jednej iteracji wypisuje na raz cała linijkę (Tobie się tak wydaje). Jednak sprawne oko bez problemu zauważy, że po uruchomieniu tego programu, zbiór znaków rysuje się na naszych oczach (a my chcemy, aby się pojawił).

Tak naprawdę, to strumień "cout" jest powolny. Pewnie dlatego, że jest buforowany. Dlatego do szybkiego wypisywania tekstu do konsoli należy korzystać z niskopoziomowych funkcji systemowych. Jedną z nich jest należąca do WinAPI WriteConsole. Oczywiście to działa tylko na Windowsie, a korzystamy z tego tak:

#include <Windows.h>

for( int i = 0; i < 15; i++ )
	WriteConsole( GetStdHandle( STD_OUTPUT_HANDLE ), string(50, '#').c_str(), 50, NULL, NULL );

To może dla Ciebie wyglądać niesamowicie skomplikowanie. Szczególnie dlatego, że dopiero jak wspomniałeś zaczynasz naukę programowania. Chciałem Ci tylko uświadomić, że im bardziej niskopoziomowo będziemy pisać, tym szybszy będzie kod. Rezygnujemy wtedy z wielu funkcjonalności. Strumień "cout" poza tym, że jest wolny, jest też niesamowicie rozbudowany. Potrafi przecież wypisywać liczby z dokładnością do danej liczby miejsc po przecinku, potrafi wypisać liczbę w zapisie szesnastkowym i wiele, wiele więcej.

Jeszcze wydajniej moglibyśmy zrezygnować z powyższej pętli for i cały zbiór znaków zapisać w jednym stringu aby następnie jako całość go wypisać. Miej jednak świadomość, że nawet taka niskopoziomowa funkcja jak WriteConsole wypisuje znak po znaku. Musi, bo nie da się na raz wielu wartości przekazać od tak, już, BACH i jest. Niestety :-)

PS. Powyżej zastosowałem zapis: string( 50, '#' ).c_str(). Jest to to samo, jakbym wkleił w to miejsce "######..." 50 takich znaków '#'. Jest to jawne wywołanie konstruktora klasy string. Ktoś może zarzucić, że takie zastosowanie konstruktora jest wolniejsze niż jawne wpisanie w kodzie 50 znaków '#'. Pewnie taka osoba miałaby rację, ale pokalanie swojego kodu takimi długimi tablicami znaków jest nieeleganckie :-P

komentarz 5 stycznia 2016 przez notabigthreat Mądrala (7,060 p.)
edycja 5 stycznia 2016 przez notabigthreat

-1 za "wydajność". Optymizacje przeprowadza się kiedy wiadomo, że program jest zbyt wolny. Kod zaciemniony, jednocześnie uzależniony od winapi gorzej się czyta, pisze, zmienia. Nie trochę za wysoka cena za oszczędzone 10ms?

Pętla wolna? Jest loop unrolling.

W praktyce wybrałbym ten krótszy zapis, bo po pierwsze widać ile znaków, po drugie wpływ na wydajność jest znikomy. Przy typowej ilości czynności wejścia/wyjścia zmiany nie są odczuwalne.

I po co takie rzeczy pisać nowicjuszowi?


Jeżeli naprawdę chcecie zwiększyć szybkość wypisywania, można wyłączyć kompatybilność ze starymi metodami (na przykład printf) , przy założeniu, że ich nie używamy:

std::ios::sync_with_stdio(false);

Dzięki temu kod się nie zaciemnia.


Na koniec może odeślę do c2:
http://c2.com/cgi/wiki?OptimizeLater

komentarz 5 stycznia 2016 przez Sebastian Fojcik Nałogowiec (43,040 p.)
Kiedy pisałem przejrzyste menu w konsoli obsługiwane strzałkami, to szybkość rysowania była niezwykle istotna. Szczególnie przy szybkim poruszaniu się między okienkami. Tak, okienkami w konsoli. Można? Można :-P

Musiałem pozbyć się efektu rysowania się tekstu na oczach użytkownika, aby nie było tzw. "migania" między wyczyszczeniem ekranu a narysowaniem nowego menu. Takie praktyki przyspieszania wypisywania stosuje się też do konsolowych mini-gierek pokroju snake czy tetris.

Celem pokazania kodu z WinAPI było zaprezentowanie jak wygląda niskopoziomowa funkcja wprost z biblioteki systemowej Windowsa. To był przykład -_-
Nigdzie absolutnie nie zachęcałem aby zastąpić tym strumienie "cout", a mam wrażenie, że tak właśnie to odebrałeś

Musisz mi uwierzyć na słowo, że pisząc w konsoli menusy lub gierki, każde 10 ms rysowania dłużej, ma znaczenie. Głównie dlatego, że przed narysowaniem nowej rzeczy trzeba wyczyścić cały ekran konsoli, a użytkownik nie może tego zauważyć :-P
komentarz 5 stycznia 2016 przez Sedi Stary wyjadacz (10,200 p.)
@notabigthreat, a ja uważam, że optymalizacja jest procesem dla użytkownika, a nie dla kodera. Zauważ, że kod piszemy nie dla siebie, ale dla użytkownika. I druga kwestia, zauważ, że w przy dużych projektach, niezależnie od tego, czy byś napisał std::cout(...), czy tą pętlę i tak traci się przejrzystość kodu. I nikt poza piszącym tego kodu nie zrozumie.

Daję plusa Sebastianowi, by miał +5 ;]

(OFFTOP)PS. Sebastian, Ty 2 tygodnie nie miałeś 10k punktów ? Ale się rozwinąłeś ?:)

Pozdrawiam :)
komentarz 5 stycznia 2016 przez notabigthreat Mądrala (7,060 p.)
@Sebastian To pewnie dlatego, że rysowałeś wszystko od początku zamiast nadpisywania tylko zmienionych znaków (wtedy nie ma migania). Jest '\r', '\b', z winapi też coś się znajdzie.

@Sedi Nikt poza piszącym kod go nie zrozumie? Czyli piszesz, że kod zawsze jest nieczytelny? Bezsensowna, niewielka optymalizacja jest dla nikogo.
prostszy kod -> szybsze czytanie/rozumienie/rozwój/poprawianie/zmiany -> zadowolony użytkownik

Wolę, zarówno jako koder i użytkownik, szybkość rozwoju od szybkości działania, jeśli tylko ta druga jest wystarczająca.
komentarz 6 stycznia 2016 przez Sedi Stary wyjadacz (10,200 p.)
Oczywiście, że masz rację i w miarę możliwości, starać się pisać funkcje, które są czytelne, bez komentarzy i jeszcze kilka innych dobrych praktyk... Nie zmienia to faktu, że jeśli mamy wybierać między kodem czytelnym ale nieoptymalnym, a kodem nieczytelnym a optymalnym. Lepiej wybrać ten drugi. Dobry przykład to quicksort i bubble sort. Bubble sort jest bardziej logiczny i prosty, ale quicksort jest piekielnie szybki, ale w czytelności różnią się :P

Pozdrawiam :)
+2 głosów
odpowiedź 5 stycznia 2016 przez Dash Nałogowiec (29,650 p.)
Uzupełniając wypowiedź kolegi dodam tylko o programowaniu współbieżnym. Jest to troszeczkę wyższy poziom, pozwala jednak na wykonywanie kilku czynności w pewnym sensie na raz. Ogólnie chodzi o rozdzielenie zadań pomiędy poszczególne rdzenie procesora.
komentarz 5 stycznia 2016 przez Sebastian Fojcik Nałogowiec (43,040 p.)

Tak sądziłem, że ktoś wspomni o pracy na kilku rdzeniach jednocześnie i właśnie dlatego zabezpieczyłem się słowem "Praktycznie nic.." :-)

Programowanie współbieżne, to temat woda. Takie praktyki mają wiele zastosowań. Fajnie napisałeś: "Jest to troszeczkę wyższy poziom"

Pisząc "Praktycznie" miałem na myśli to, że system analizuje kod programu po kolei. Instrukcja po instrukcji. Jedynie procesor może na kilku rdzeniach policzyć coś jednocześnie. Jednak system nadal może w jednym wątku odebrać na raz tylko jedną policzoną wartość i później dopiero kolejną.

Jeśli pomyliłem się pisząc tutaj, że to system analizuje kod programu i odbiera policzoną wartość, to śmiało mnie popraw, bo nie opieram tej wiedzy o żadną literaturę.

Dzięki za dopowiedzenie :-)

+1 głos
odpowiedź 5 stycznia 2016 przez Dorion300 Szeryf (90,250 p.)
tak, operacje są liniowe. (no chyba że posiadasz wielordzeniowy procesor i tworzysz wątki)

zauważ że najpierw podnosisz wszystkie klocki, a potem renderujesz.

Działa to tak szybko że po prostu czuć że program robi wiele rzeczy na raz.

Podobne pytania

–1 głos
1 odpowiedź 149 wizyt
0 głosów
1 odpowiedź 457 wizyt

92,580 zapytań

141,433 odpowiedzi

319,665 komentarzy

61,965 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...