Materiały do pisania programów asynchronicznych

0

Czy można prosić o książki, tutoriale, cokolwiek na temat pisania programów asynchronicznych ?

3
zkubinski napisał(a):

Czy można prosić o książki, tutoriale, cokolwiek na temat pisania programów asynchronicznych ?

A co to jest program asynchroniczny?

0
Riddle napisał(a):
zkubinski napisał(a):

Czy można prosić o książki, tutoriale, cokolwiek na temat pisania programów asynchronicznych ?

A co to jest program asynchroniczny?

z tego co słyszałem, to program który NIE wykonuje się linijka po linijce od góry do dołu

4

Chyba za wcześnie na asynchroniczność dla ciebie.

1

Dostałeś ode mnie listę polecanych lektur i kolejności ich czytania. Nie przeczytałeś ich jeszcze. Nie widzę potrzeby zatem dodawania kolejnych na stos, zwłaszcza że jedna z tych książek omawia std::async i jego zastosowania.

1
zkubinski napisał(a):
Riddle napisał(a):

A co to jest program asynchroniczny?

z tego co słyszałem, to program który NIE wykonuje się linijka po linijce od góry do dołu

@zkubinski, coś w ten deseń:

#include <iostream>
using namespace std;

int main()
{
    goto start;
    kota: cout<<"kota"; goto end;
    start: cout<<"Ala "; goto ma;
    end: cout<<endl; goto ret;
    ma: cout<<"ma "; goto kota;
    ret: return 0;
}

?

2

Ad 1. Przykłady bez sensu, np: po kiego asynchronicznie zliczać jeżeli tuż za pętlą masz .join() zrozumiałbym gdyby każdy z wątków zliczałby sumę częściową aby po tym .join() wyliczyć sumę wspólną.
Ad 2. To odpowiedzi na jedno konkretne pytanie

Dla ciebie za wcześnie, ty wciąż się gubisz w if'ach i prostych pętlach.

0

Tutaj jest opisane podejście kooperatywnego przełączania zadań. Wtedy nie trzeba martwić się zbytnio o różne ‘locki’. Ciekawe, co myślisz o takim podejściu na początek zamiast wątków.

4

@zkubinski:

GDYBYŚ , ale to tak warunkowo, wiem ze to niemożliwe, przemedytował do spodu Qt, to miałbyś podstawie oswojenie z pojęciem asynchroniczności, i pytania by były mniej dziwne

https://www.google.com/search?q=qt+asynchronous+function+call

0

Ta asynchroniczność jest dość ciężkim tematem, najłatwiej korzystać po prostu z tego std::async implementacji.

Ogólnie odczyt danych od użytkownika jest synchroniczny standardowo, można poprosić system żeby był asynchroniczny, nieblokujący zwraca informacje czy są dane czy nie.

Kernel sprawdza czy są dane jak nie ma to robi wait_queue, a jak masz nieblokujący to zwraca zero od razu i wychodzi.

I teraz jak masz program to robisz jakieś swoje renderowania gui, jakieś drobne prace, a potem sobie sprawdzasz czy są jakieś dane do obsłużenia, jakbyś miał blokujące funkcje to byś musiał robić nowy wątek.
W javascript jest to tak rozwiązane, że zleca się zadania do event queue i ustawia promisce , wykonuje swoje prace i potem wraca się do tej kolejki i je znowu wykonuje żeby nie blokować wcześniejszych.

Są też green thready czyli jakieś takie super lekkie thready, proces to wiadomo ma własną pamięć i wszystko, thread współdzieli przez co nie trzeba kopiować.

taki std::async może być różnie implementowany zwykle jest to nowy thread.

W innych językach mogą inaczej to zaimplementować, ogólnie rozchodzi się o to, żeby różne wykonania kodu działały równocześnie i żaden siebie nie mógł blokować, nawet jak jest jakiś blokujący.

Ogólnie nie wiem jak są zbudowane promisce w javascript, prawdopodobnie żeby to tak zbudować promisce musi być obiektem, który jest dodawany do kolejki, i zawiera swój stan, ten stan jest sprawdzany za każdym przejsciem po event loop, po skończeniu jakiś podstawowych operacji i jeśli stan się nie zmienił promisca to jest pomijany, a jeśli się zmienił, bo jest patternem typu subscriber, zostawia callback dla silnika, który to zewnętrzny thread silnika odpala lub coś, w tym wypadku po zleceniu zapytania i jego odebraniu wywołuje operację zmiany stanu tego obiektu.

Na poziomie kernela możesz tylko procesy i wątki robić, jeśli chcesz green thready robić to musisz trochę się mega nagimnastykować żeby zrobić softwarowy multithreading.

0

Nie jestem dobry w C++, ale sądzę, że jeżeli chcesz to robić w C++ to dobrze było by ogarnąć to najpierw w "gołym" C. Ogólnie sądzę, że nauka C++ bez znajomości C jest trudna. W C wszystko jest łatwiejsze do zrozumienia. A jak już zrozumiesz jak robi się asynchroniczność w C to C++ będzie dla Ciebie "narzędziem" ułatwiającym pracę i zwiększającym produktywność.

Poza tym, jak ktoś wyżej zauważył - na razie jeszcze dobrze nie wiesz czym jest asynchroniczność w oprogramowaniu.

Tu masz coś co może się przydać (fajny wstęp do event-driven programming):

1
Kamil A napisał(a):

Nie jestem dobry w C++, ale sądzę, że jeżeli chcesz to robić w C++ to dobrze było by ogarnąć to najpierw w "gołym" C. Ogólnie sądzę, że nauka C++ bez znajomości C jest trudna. W C wszystko jest łatwiejsze do zrozumienia. A jak już zrozumiesz jak robi się asynchroniczność w C to C++ będzie dla Ciebie "narzędziem" ułatwiającym pracę i zwiększającym produktywność.

Tak / nie / zależy

C jest asemblerem z funcją printf, w jakimś sensie bazą reszty świata (np Javy, skoro pra kompilator C++ był napisany w C, a JVM jest w C++).
C (myślany jako kompatybilny z potencjanymi wstawkami ASM, rozumieniem bajt po bajcie, rozkaz po rozkazie), tak w sensie tego wątku dyskusji, oswaja z rzeczywistym CPU wykonującym kod. Aż tyle i tylko tyle.

Z drugiej ...
Przygotowanie do jakiejś zestandaryzowanej asynchroniczności nie ma tam prawie wcale - oprócz generalnego oswojenia z ramką, stosem, wątkiem, przerwaniem (dla piszących embedded C czy wymarłymi autorami "programów rezydentnych" w DOS). Jakiś setjmp / longjmp (nie asynchroniczne, ale otwierają oczy na pewną rzeczywistość)

Dla mnie jakieś sensowne w XXIw programowanie asynchroniczne to obietówka (w tym funkcyjne które bardzo naturalnie wyrażają współczesne pr.asyn. - silniki funkcyjne są zbudowane chyba wszystkie w j.obiektowych) - koncepcje jakby "asynchroniczne" w C są naprawdę "ręczne" z lat 1970ch
O ile w C można programować w (w zasadzie) obiektowo, nie ma odśmiecacza, automatycznie zwalnianych pointerów czasem zwanymi smart / równoważnika np Rust itd, co do rzucania obiektem Future jest "dość ważne". Wysyłając coś w przyszłość, musimy mieć przekonanie, że w miare możliwości nad tym panujemy.
Dużym minusem C jest brak enkapsulacji np pól struktur (ciężko mówić o standaryzacji bezpiecznego API "używaj wyłącznie tego") a konstruktor jest "ręczny"

0

Prosty przykład obliczeń równoległych https://pl.wikipedia.org/wiki/Szereg_harmoniczny :

#include <iostream>
#include <iomanip>
#include <thread>
#include <vector>
#include <unordered_map>
using namespace std;
using namespace std::chrono;

const int precision=12;

enum class Method:uint8_t { Simple,Thread };

class harmonic
{
	public:
	typedef void (harmonic::*member)();
	using callpair=pair<string,member>;
	using methodmap=unordered_map<Method,callpair>;
	private:
	double sum;
	unsigned long count;
	unsigned nr,step;
	static callpair &map(Method method)
	{
		static methodmap m
		{
			{Method::Simple,callpair{"Simple",&harmonic::simplecalc}},
			{Method::Thread,callpair{"Thread",&harmonic::threadcalc}},
		};
		return m[method];
	}
	public:
	harmonic(unsigned long count,unsigned nr=0,unsigned step=1):sum(0),count(count),nr(nr),step(step) {}
	void simplecalc()
	{
		sum=0;
		for(unsigned long i=1+nr;i<=count;i+=step) sum+=1/(double)i;
	}
	static void partcalc(double *sum,unsigned long count,unsigned nr,unsigned step)
	{
		harmonic h(count,nr,step);
		h.simplecalc();
		*sum=h.sum;
	}
	void threadcalc()
	{
		unsigned thc=thread::hardware_concurrency();
		vector<double> parts(thc);
		vector<thread> thv;
		thv.reserve(thc);
		sum=0;
		for(unsigned nr=0;nr<thc;++nr) thv.emplace_back(partcalc,&parts[nr],count,nr,thc);
		for(unsigned nr=0;nr<thc;++nr) thv[nr].join();
		for(unsigned nr=0;nr<thc;++nr) sum+=parts[nr];
	}
	static void show(Method method,unsigned long count)
	{
		auto start=high_resolution_clock::now();
		harmonic hs(count);
		callpair cp=map(method);
		(hs.*cp.second)();
		auto stop=high_resolution_clock::now();
		auto duration=duration_cast<milliseconds>(stop-start);
		cout
			<<cp.first
			<<setw(12)<<count
			<<": "
			<<setw(3+precision)<<setprecision(precision)<<hs.sum
			<<setw(10)<<duration.count()
			<<"ms"
			<<endl
		;
	}
};

int main()
{
	while(true)
	{
		cout<<"Input count (negative count - run thread calc): ";
		long count;
		cin>>count;
		if(count>0) thread{harmonic::show,Method::Simple,+count}.join();
		else        thread{harmonic::show,Method::Thread,-count}.join();
	}
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1