Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: DragoRosso - Ottobre 16, 2021, 12:34:52 pm

Titolo: Metodi bloccanti e non bloccanti
Inserito da: DragoRosso - Ottobre 16, 2021, 12:34:52 pm
Ciao a tutti, oggi apro un topic il cui argomento non è molto discusso nell'ambito della programmazione, però l'ho sempre trovato abbastanza "ostico", sopratutto se vengono sviluppati progetti di un certo tipo. Quello che descrivo è tipico degli ambienti Windows, portare un paragone anche per ambienti diversi quali Linux, Mac, o Android sarebbe interessante.

Portate il Vs. contributo alla discussione.

Quando chiamiamo un metodo, sia esso una procedura, una funzione, una proprietà o quant'altro, come facciamo a sapere se il metodo è bloccante (io lo chiamerei sincrono) o non bloccante (asincrono)?

In pratica io chiamo un metodo e questo produce degli effetti: questi effetti sono immediati ? il metodo ritorna con la funzione eseguita o la funzione verrà eseguita tramite lo schedulatore di sistema?

In genere ciò che ha che fare con la grafica, in particolare con le form e i componenti relativi, sono metodi asincroni (non bloccanti). Ad esempio quando chiamiamo il metdo "Form1.Invalidate" questo informa il componente che dovrà essere "ridisegnato", ma l'azione verrà svolta in un secondo momento.
Anche i metodo Repaint e Refresh, per quanto vengano indicati come immediati in realtà accellerano il processo ma sono comunque asincroni.
Per questi metodi quindi è necessario tenere presente che l'effetto non l'avremo pronto alla riga successiva del "sorgente", ma un pò più in là.

Non è cosa da poco, moltissimi bachi, anche importanti riscontrati da Microsoft e da altre case di produzione di ambienti di sviluppo riguardano proprio queste condizioni dove potrebbero innescarsi dei loop disastrosi.

Sapere se un metodo è sincrono all'esecuzione del ns. programma o asincrono però è importante sopratutto dove vengono svolte applicazioni con richieste prestazionali elevate.

Sapere se è necessario attendere o rilevare una callback per l'esecuzione del codice successivo è importante per non perdere tempo o adirittura per non rischiare di avere condizioni inconsistenti.

Per fare un esempio più chiaro, nei processori moderni tutte le esecuzioni delle istruzioni vengono eseguite in maniera asincrona e la sequenza non è garantita: una operazione matematica ad esempio viene eseguita in parallelo ad altre, ma il processore garantisce che l'istruzione che accede al risultato abbia 
accesso al dato corretto, usando diversi meccanismi interni al processore stesso.
Sono pochissime le istruzioni sincrone nei processori moderni.

Nelle applicazioni ad alto livello invece questi meccanismi non ci sono (se io scrivo nel sorgente una riga prima o dopo le cose cambiano radicalmente e devo io stare attento alla sequenza ovviamente).

Io ho trovato sempre ostico (anche se ormai con l'esperienza questi argomenti sono abbastanza relativi)  capire se un metodo è sincrono o asincrono, perchè molto spesso (anzi quasi sempre) la documentazione non è chiara su questi aspetti.

Voi avete rilevato problematiche simili? Sapete come rilevare se un metodo è sincrono o asincrono? Avete escogitato dei "sistemi" per evitare tali situazioni?

Ciao
Titolo: Re:Metodi bloccanti e non bloccanti
Inserito da: bonmario - Ottobre 16, 2021, 07:50:44 pm
Da autodidatta, direi che l'unico modo per saperlo a priori, è quello di guardare la documentazione, sperando che ci sia su quell'argomento, e che ci sia scritta questa informazione.
In Lazarus/FPC, essendo open source, si può trovare la risposta spulciando i sorgenti.

Ciao, Mario
Titolo: Re:Metodi bloccanti e non bloccanti
Inserito da: SB - Ottobre 17, 2021, 09:46:27 am
Argomento interessante e fonte di problemi.
Provo a dare un piccolo contributo.
L'asincronismo di norma può esserci se ci sono flussi di esecuzione paralleli e la comunicazione tra processi/thread è di tipo a messaggi (altrimenti di solito sono previsti meccanismi di sincronizzazione).
A priori si può dire ben poco visto che in linea di principio lo scopo di realizzare un metodo da invocare è anche quello di nasconderne l'implementazione.
Però una conoscenza di massima di come funziona il sistema dietro le quinte può essere di aiuto.
Ad esempio l'interfaccia grafica (tutte, che io sappia) è gestita a messaggi per poter gestire anche eventi esterni all'applicazione, e quindi si può presumere che l'esecuzione sia asincrona salvo non sia diversamente specificato.
In altri casi senza documentazione penso sia difficile/impossibile stabilire con quale modalità è stato implementato un metodo. In questo caso il non documentare l'asincronicità sarebbe una grave colpa degli sviluppatori

Sapere se un metodo è sincrono all'esecuzione del ns. programma o asincrono però è importante sopratutto dove vengono svolte applicazioni con richieste prestazionali elevate.

Sapere se è necessario attendere o rilevare una callback per l'esecuzione del codice successivo è importante per non perdere tempo o adirittura per non rischiare di avere condizioni inconsistenti.

Se ho inteso correttamente, direi che i sistemi operativi normalmente utilizzati (windows, linux, ecc) non sono real time. Si possono ottenere "prestazioni elevate" solo potenziando l'hardware in modo da nascondere la loro intrinseca indeterminatezza.
Che io sappia dove si ha bisogno di sfruttare al massimo l'hardware si ricorre, ad esempio, a versioni (molto) modificate di linux (con linux solo per questioni di accesso al sorgente).
Penso che per ottenere prestazioni elevate sia necessario sfruttare ampiamente l'asincronicità, ma immagino che l'approccio allo sviluppo di applicazioni diventi molto diverso da quello adottato "normalmente".

Per fare un esempio più chiaro, nei processori moderni tutte le esecuzioni delle istruzioni vengono eseguite in maniera asincrona e la sequenza non è garantita: una operazione matematica ad esempio viene eseguita in parallelo ad altre, ma il processore garantisce che l'istruzione che accede al risultato abbia 
accesso al dato corretto, usando diversi meccanismi interni al processore stesso.
Sono pochissime le istruzioni sincrone nei processori moderni.

Non confonderei elettronica e informatica.
Un conto è la circuiteria interna dei processori e un conto è l'esecuzione logica delle istruzioni.
Le istruzioni devono essere sincrone dal punto di vista dell'esecuzione altrimenti salta il determinismo dei processori e avremmo macchine casuali.
Sarebbe un bel guaio.

Nelle applicazioni ad alto livello invece questi meccanismi non ci sono (se io scrivo nel sorgente una riga prima o dopo le cose cambiano radicalmente e devo io stare attento alla sequenza ovviamente).

Mi approccerei al problema in maniera diversa.
L'esecuzione asincrona è un vantaggio, non uno svantaggio.
Viene offerta per sfruttare il parallelismo e quindi avere un utilizzo più efficiente dell'hardware, sia su singolo computer che su più computer in rete.
E' una di quelle cose che evidenzia come lo sviluppo di applicazioni richiede grande professionalità ed esperienza




Titolo: Re:Metodi bloccanti e non bloccanti
Inserito da: DragoRosso - Ottobre 17, 2021, 12:56:53 pm
Penso che per ottenere prestazioni elevate sia necessario sfruttare ampiamente l'asincronicità, ma immagino che l'approccio allo sviluppo di applicazioni diventi molto diverso da quello adottato "normalmente".

Si, è come dici. L'approccio, ancorchè sfrutta strumenti standard, è un pò diverso. Il codice in questo caso potrebbe essere scritto quasi "a caso" come sequenzialità e si sfrutta invece tutta la potenza dei threads e dei meccanismi di sincronismo e di bilanciamento del carico.

Che io sappia dove si ha bisogno di sfruttare al massimo l'hardware si ricorre, ad esempio, a versioni (molto) modificate di linux (con linux solo per questioni di accesso al sorgente).

Non necessariamente. Io uso un normalissimo Windows, anche Home alle volte, per fare sistemi industriali ad elevatissime prestazioni. Basta come dici tu studiare bene l'hardware e usare le periferiche corrette. Accedere a timer con risoluzione di di mezzo nanosecondo e usarlo in applicazioni sotto Windows è possibile (magari solo per debug), l'importante è sapere cosa si stà facendo e cosa implica tutto ciò. Ma qui siamo oltre lo scopo di questa discussione.
Inoltre occorre conoscere anche l'elettronica, in particolarei almeno i fondamenti dei processori moderni ....

Non confonderei elettronica e informatica.
Un conto è la circuiteria interna dei processori e un conto è l'esecuzione logica delle istruzioni.
Le istruzioni devono essere sincrone dal punto di vista dell'esecuzione altrimenti salta il determinismo dei processori e avremmo macchine casuali.

.... riprendendo dal passo precedente, conoscere tecniche come le pipeline, il branch prediction, il cahce invalidation, l'esecuzione out of order e speculativa, etc.... consente di avere molto più chiaro il funzionamento generale di un "processo" e di poter gestire al meglio il codice.
Ovvio che tali informazioni fanno parte del bagaglio culturale di una persona e anche senza queste info un programmatore può essere sicuramente un ottimo programmatore.

Mi approccerei al problema in maniera diversa.
L'esecuzione asincrona è un vantaggio, non uno svantaggio.
Viene offerta per sfruttare il parallelismo e quindi avere un utilizzo più efficiente dell'hardware, sia su singolo computer che su più computer in rete.
E' una di quelle cose che evidenzia come lo sviluppo di applicazioni richiede grande professionalità ed esperienza.

Concordo con te, la mia affermazione si riferiva al fatto che a livello di macro codice (ad esempio PASCAL) ovviamente in questo momento non c'è un meccanismo come quello di un processore.

Ciao ciao
Titolo: Re:Metodi bloccanti e non bloccanti
Inserito da: nomorelogic - Ottobre 18, 2021, 02:30:18 pm

Mi approccerei al problema in maniera diversa.
L'esecuzione asincrona è un vantaggio, non uno svantaggio.
Viene offerta per sfruttare il parallelismo e quindi avere un utilizzo più efficiente dell'hardware, sia su singolo computer che su più computer in rete.
E' una di quelle cose che evidenzia come lo sviluppo di applicazioni richiede grande professionalità ed esperienza.

Concordo con te, la mia affermazione si riferiva al fatto che a livello di macro codice (ad esempio PASCAL) ovviamente in questo momento non c'è un meccanismo come quello di un processore.

Ciao ciao

oltre ai thread, in realtà ci sono comuque funzionalità che si possono sfruttare nei linguaggi ad alto livello tipo futures, async, await e compagnia
non tutti i linguaggi li hanno, è vero, ma spesso si può ovviare implementando queste funzionalità con thread e semafori
con il fatto che i programmi accedono sempre di più alle risorse in rete, queste tecniche saranno col tempo sempre più utilizzate anche nei linguaggi ad alto livello



riguardo invece il disegno della GUI di un programma, quello è gestito con una coda di modo che ci sia sempre un solo processo che si occupa del disegno (in Lazarus è il main thread)
per fare il refresh della gui si può forzare l'elaborazione di tutti gli elementi della coda (Application.ProcessMessages)



Edit:
giusto per conoscenza, non l'ho mai utilizzata ma sembra una libreria molto promettente
https://github.com/mr-highball/ezthreads (https://github.com/mr-highball/ezthreads)
Titolo: Re:Metodi bloccanti e non bloccanti
Inserito da: DragoRosso - Ottobre 18, 2021, 03:37:26 pm
riguardo invece il disegno della GUI di un programma, quello è gestito con una coda di modo che ci sia sempre un solo processo che si occupa del disegno (in Lazarus è il main thread)
per fare il refresh della gui si può forzare l'elaborazione di tutti gli elementi della coda (Application.ProcessMessages)

Per questo normalmente tutto ciò che riguarda la parte grafica è asincrona.

oltre ai thread, in realtà ci sono comuque funzionalità che si possono sfruttare nei linguaggi ad alto livello tipo futures, async, await e compagnia
non tutti i linguaggi li hanno, è vero, ma spesso si può ovviare implementando queste funzionalità con thread e semafori
con il fatto che i programmi accedono sempre di più alle risorse in rete, queste tecniche saranno col tempo sempre più utilizzate anche nei linguaggi ad alto livello

Async, await: bhè diciamo che nella maggior parte delle applicazioni il normale uso di funzioni "not blocking" e l'uso degli eventi (WaitFor) fà già molto per non dire tutto (forse sono più utili nella applicazioni web), sui future (così con i promise) sono da "scienziato" universitario e implica una logica che sinceramente non ho mai applicato e che faccio fatica a comprendere (più che altro a come applicarla nel concreto).

Il link indicato penso che riguardi una delle implementazioni della tecnica del "ThreadPool".
Vanno benissimo per fare svariati lavori dove non è necessario una ottimizzazione spinta o molto specializzata, ma ancora adesso (almeno per quel che mi riguarda) l'uso dei classici Thread è ancora ineguagliabile.

La possibilità di usare in questi ultimi alcune peculiarità di SO (ad esempio la priorità "Time Critical") li rende ancora insostituibili.
Sono vecchio lo sò ... lunga vita ai vecchi  ;D

Ciao
Titolo: Re:Metodi bloccanti e non bloccanti
Inserito da: nomorelogic - Ottobre 18, 2021, 04:01:59 pm
il link è ad una libreria per la gestione dei thread pool
c'è implementata anche la dipendenza tra thread, per cui un thread prima di essere eseguito completamente deve attendere che ne sia completato un altro

diciamo che è già tanto anche perché se posso 'ste cose le evito come la peste :D