PHP ha threading?


130

Ho trovato questo pacchetto PECL chiamato thread , ma non esiste ancora una versione. E non sta succedendo nulla sul sito Web di PHP.


Qualcuno sa se questo ( pcntl_fork()) funzionerà se chiamato da Apache?
Josh K,

Questo è incredibilmente vecchio, ma ho una risposta che in realtà fornisce thread in php (vedi sotto per i link).
Alec Gorge,

Raccomandano di non chiamare fork da un ambiente server. Non li biasimo. Tuttavia, pcntl_fork sembra essere la migliore soluzione per il threading di PHP.
just_wes

Sì, non dovresti aver bisogno di fork di un processo php apache2.
andho,

2
Usa pthreads funziona come un incantesimo
Baba,

Risposte:


40

Non c'è nulla di cui io sia a conoscenza. La prossima cosa migliore sarebbe semplicemente far eseguire uno script a un altro tramite CLI, ma è un po 'rudimentale. A seconda di cosa stai cercando di fare e di quanto sia complesso, questa potrebbe essere o meno un'opzione.


1
È quello che pensavo. Ho visto un sacco di post precedenti che dicevano no e niente su php.net, quindi questo era il mio pensiero. Grazie per averlo confermato.
Thomas Owens,

2
Sì, quel pacchetto PECL è una specie di presa in giro - l'ho incontrato anche io ma non ne è mai uscito nulla.
Wilco,

180

Dal manuale di PHP per l' estensione pthreads :

pthreads è un'API orientata agli oggetti che consente il multi-threading user-land in PHP. Include tutti gli strumenti necessari per creare applicazioni multi-thread destinate al Web o alla console. Le applicazioni PHP possono creare, leggere, scrivere, eseguire e sincronizzare con Thread, Lavoratori e Stackable.

Per quanto incredibile possa sembrare, è del tutto vero. Oggi PHP può eseguire il multi-thread per coloro che desiderano provarlo.

La prima versione di PHP4, 22 maggio 2000, PHP è stata fornita con un'architettura thread-safe: un modo per eseguire più istanze del suo interprete in thread separati in ambienti SAPI (Server API) multi-thread. Negli ultimi 13 anni, il design di questa architettura è stato mantenuto e avanzato: da allora è in uso nella produzione sui più grandi siti Web del mondo.

Il thread nella terra degli utenti non è mai stato un problema per il team di PHP, e lo è ancora oggi. Dovresti capire che nel mondo in cui PHP fa affari, esiste già un metodo di ridimensionamento definito: aggiungere hardware. Nel corso degli anni PHP è esistito, l'hardware è diventato sempre più economico e quindi questo è diventato sempre più un problema per il team PHP. Mentre stava diventando più economico, divenne anche molto più potente; oggi, i nostri telefoni cellulari e tablet hanno architetture dual e quad core e molta RAM per andare con esso, i nostri desktop e server hanno comunemente 8 o 16 core, 16 e 32 gigabyte di RAM, anche se potremmo non essere sempre in grado di avere due nel rispetto del budget e avere due desktop raramente è utile per la maggior parte di noi.

Inoltre, PHP è stato scritto per i non programmatori, è la lingua madre di molti hobbisti. Il motivo per cui PHP è così facilmente adottato è perché è una lingua facile da imparare e scrivere. Il motivo per cui PHP è così affidabile oggi è a causa della grande quantità di lavoro che viene svolto nella sua progettazione e di ogni singola decisione presa dal gruppo PHP. La sua affidabilità e la sua straordinaria grandezza lo tengono sotto i riflettori, dopo tutti questi anni; dove i suoi rivali sono caduti nel tempo o nella pressione.

La programmazione multi-thread non è facile per la maggior parte, anche con l'API più coerente e affidabile, ci sono diverse cose a cui pensare e molte idee sbagliate. Il gruppo PHP non desidera che il multi-threading di terra dell'utente sia una caratteristica fondamentale, non gli è mai stata prestata molta attenzione, e giustamente. PHP non dovrebbe essere complesso, per tutti.

Tutto sommato, ci sono ancora vantaggi nel consentire a PHP di utilizzare le sue funzionalità pronte per la produzione e testate per consentire un modo per ottenere il massimo da ciò che abbiamo, quando aggiungere di più non è sempre un'opzione e per molto di compiti non è mai veramente necessario.

pthreads realizza, per coloro che desiderano esplorarlo, un'API che consente a un utente di utilizzare applicazioni PHP multi-thread. L'API è in fase di sviluppo e ha designato un livello beta di stabilità e completezza.

È risaputo che alcune delle librerie utilizzate da PHP non sono thread-safe, dovrebbe essere chiaro al programmatore che pthreads non può cambiarlo e non tenta di provare. Tuttavia, è possibile utilizzare qualsiasi libreria protetta da thread, come in qualsiasi altra configurazione dell'interprete thread-safe.

pthreads utilizza i thread Posix (anche in Windows), ciò che il programmatore crea sono veri e propri thread di esecuzione, ma affinché questi thread siano utili, devono essere consapevoli di PHP - in grado di eseguire codice utente, condividere variabili e consentire un utile mezzo di comunicazione (sincronizzazione). Quindi ogni thread viene creato con un'istanza dell'interprete, ma per impostazione predefinita, il suo interprete è isolato da tutte le altre istanze dell'interprete, proprio come gli ambienti API Server multi-thread. pthreads tenta di colmare il divario in modo sano e sicuro. Molte delle preoccupazioni del programmatore di thread in C non sono lì per il programmatore di pthreads, in base alla progettazione, pthreads è copia su lettura e copia su scrittura (la RAM è economica), quindi non ci sono mai due casi che manipolano gli stessi dati fisici , ma entrambi possono influire sui dati in un altro thread.

Perché copiare su lettura e copia su scrittura:

public function run() {
    ...
    (1) $this->data = $data;
    ...
    (2) $this->other = someOperation($this->data);
    ...
}

(3) echo preg_match($pattern, $replace, $thread->data);

(1) Mentre un blocco di lettura e scrittura sono conservati nell'archivio dati oggetto pthreads, i dati vengono copiati dalla loro posizione originale in memoria nell'archivio oggetti. pthreads non regola il refcount della variabile, Zend è in grado di liberare i dati originali se non ci sono ulteriori riferimenti ad esso.

(2) L'argomento di someOperation fa riferimento all'archivio oggetti, i dati originali memorizzati, che a sua volta una copia del risultato di (1), vengono nuovamente copiati per il motore in un contenitore zval, mentre in questo caso viene mantenuto un blocco di lettura l'archivio oggetti, il blocco viene rilasciato e il motore può eseguire la funzione. Quando viene creato zval, ha un nuovo conto di 0, che consente al motore di liberare la copia al completamento dell'operazione, perché non esistono altri riferimenti ad essa.

(3) L'ultimo argomento di preg_match fa riferimento all'archivio dati, si ottiene un blocco di lettura, il set di dati in (1) viene copiato in un valore zval, sempre con un refcount di 0. Il blocco viene rilasciato, la chiamata a preg_match funziona su una copia dei dati, che è essa stessa una copia dei dati originali.

Cose da sapere:

  • La tabella hash
    dell'archivio oggetti in cui sono archiviati i dati, thread-safe, si basa sulla tabella TsHash fornita con PHP da Zend.

  • L'archivio oggetti ha un blocco di lettura e scrittura, un ulteriore blocco di accesso è fornito per la TsHashTable tale che se necessario (e lo fa, var_dump / print_r, accesso diretto alle proprietà come il motore PHP vuole fare riferimento a loro) i pthreads possono manipolare la TsHashTable al di fuori dell'API definita.

  • I blocchi vengono mantenuti solo quando si verificano le operazioni di copia, quando le copie sono state eseguite, i blocchi vengono rilasciati, in un ordine ragionevole.

Questo significa:

  • Quando si verifica una scrittura, non solo viene trattenuto un blocco di lettura e scrittura, ma un blocco di accesso aggiuntivo. La tabella stessa è bloccata, non è possibile che un altro contesto possa bloccarla, leggerla, scriverla o influenzarla.

  • Quando si verifica una lettura, non solo viene mantenuto il blocco di lettura, ma anche il blocco di accesso aggiuntivo, di nuovo la tabella viene bloccata.

Nessun due contesti possono accedere fisicamente o contemporaneamente agli stessi dati dall'archivio oggetti, ma le scritture effettuate in qualsiasi contesto con un riferimento influenzeranno i dati letti in qualsiasi contesto con un riferimento.

Questa non è un'architettura condivisa e l'unico modo per esistere è la coesistenza. Quelli un po 'esperti lo vedranno, ci sono molte copie in corso qui, e si chiederanno se è una buona cosa. Molte operazioni di copiatura avvengono in un runtime dinamico, questa è la dinamica di un linguaggio dinamico. pthreads è implementato a livello dell'oggetto, perché si può ottenere un buon controllo su un oggetto, ma i metodi - il codice eseguito dal programmatore - hanno un altro contesto, privo di blocchi e copie - l'ambito del metodo locale. L'ambito dell'oggetto nel caso di un oggetto pthreads dovrebbe essere trattato come un modo per condividere dati tra contesti, questo è il suo scopo. Tenendo presente ciò, puoi adottare tecniche per evitare di bloccare l'archivio oggetti a meno che non sia necessario,

La maggior parte delle librerie ed estensioni disponibili per PHP sono thin wrapper di terze parti, la funzionalità di base di PHP è in un certo senso la stessa cosa. pthreads non è un involucro sottile attorno ai thread Posix; è un'API threading basata su thread Posix. Nell'implementazione di Thread in PHP non ha senso che gli utenti non capiscano o non possano usare. Non c'è motivo per cui una persona senza conoscenza di cosa sia o faccia un mutex non dovrebbe essere in grado di sfruttare tutto ciò che ha, sia in termini di abilità che di risorse. Un oggetto funziona come un oggetto, ma ovunque due contesti si scontrino altrimenti, pthreads fornisce stabilità e sicurezza.

Chiunque abbia lavorato in Java vedrà le somiglianze tra un oggetto pthreads e il threading in Java, quelle stesse persone non avranno alcun dubbio visto un errore chiamato ConcurrentModificationException - poiché suona un errore generato dal runtime java se due thread scrivono gli stessi dati fisici in concomitanza. Capisco perché esiste, ma mi sconcerta che con risorse economiche come sono, insieme al fatto che il runtime è in grado di rilevare la concorrenza nel momento esatto e unico che la sicurezza potrebbe essere raggiunta per l'utente, che sceglie di genera un errore potenzialmente fatale in fase di esecuzione anziché gestire l'esecuzione e l'accesso ai dati.

Nessun errore così stupido verrà emesso da pthreads, l'API è stata scritta per rendere il threading più stabile e compatibile possibile, credo.

Il multi-threading non è come usare un nuovo database, bisogna prestare molta attenzione a ogni parola del manuale e agli esempi forniti con pthreads.

Infine, dal manuale di PHP:

pthreads è stato ed è un esperimento con risultati abbastanza buoni. Qualunque delle sue limitazioni o caratteristiche può cambiare in qualsiasi momento; questa è la natura della sperimentazione. Le sue limitazioni - spesso imposte dall'implementazione - esistono per una buona ragione; lo scopo di pthreads è di fornire una soluzione utilizzabile per il multitasking in PHP a qualsiasi livello. Nell'ambiente in cui pthreads viene eseguito, alcune restrizioni e limitazioni sono necessarie per fornire un ambiente stabile.


14
Assurdità assoluta.
Joe Watkins,

7
@GeoC. Non sono nemmeno sicuro di quale sia il tuo punto qui, è solo un carico di incomprensibili e non fornisci ragioni , logiche o di altro tipo, sul motivo per cui non sei d'accordo con qualsiasi argomento (di cui non riesco davvero a vedere nessuno nel post) .
Jimbo,

13
@Tudor Non penso che tu sappia davvero di cosa stai parlando, quindi sono felice di ignorarti.
Joe Watkins,

4
@Tudor - molti scienziati non hanno "visto il punto" di qualcosa di nuovo nel loro ramo o di qualcosa di utile. La storia ha dimostrato che il più delle volte persone come te hanno semplicemente torto, è un dato di fatto. Proprio come è un dato di fatto che tutto ciò che hai scritto qui è, in mancanza di una parola migliore, feci. Consiglio vivamente, con tutti gli aspetti positivi in ​​mente, di non prendere parte ad argomenti di cui non si sa nulla (essendo questo).
NB

12
Cosa divertente. Joe Watkins è l'autore di pthreads, e ancora Tudor cerca di dimostrare che si sbaglia.
Hristo Valkanov,

48

Ecco un esempio di ciò che Wilco ha suggerito:

$cmd = 'nohup nice -n 10 /usr/bin/php -c /path/to/php.ini -f /path/to/php/file.php action=generate var1_id=23 var2_id=35 gen_id=535 > /path/to/log/file.log & echo $!';
$pid = shell_exec($cmd);

Fondamentalmente questo esegue lo script PHP dalla riga di comando, ma restituisce immediatamente il PID e quindi viene eseguito in background. (L'eco $! Assicura che non venga restituito nient'altro che il PID.) Ciò consente allo script PHP di continuare o uscire se lo si desidera. Quando l'ho usato, ho reindirizzato l'utente su un'altra pagina, dove ogni 5 a 60 secondi viene effettuata una chiamata AJAX per verificare se il report è ancora in esecuzione. (Ho una tabella per memorizzare gen_id e l'utente a cui è correlato.) Lo script check esegue quanto segue:

exec('ps ' . $pid , $processState);
if (count($processState) < 2) {
     // less than 2 rows in the ps, therefore report is complete
}

C'è un breve post su questa tecnica qui: http://nsaunders.wordpress.com/2007/01/12/running-a-background-process-in-php/


ho un leggero problema, come controllate lo stato del processo in background? puoi illuminarmi
13

25

In breve: sì, c'è il multithreading in php ma dovresti usare invece il multiprocessing.

Informazioni su Backgroud: thread vs. processi

C'è sempre un po 'di confusione sulla distinzione di thread e processi, quindi descriverò brevemente entrambi:

  • Un thread è una sequenza di comandi che la CPU elaborerà. L'unico dato di cui è costituito è un contatore di programmi. Ogni core della CPU elaborerà un solo thread alla volta, ma può passare dall'esecuzione di diversi thread tramite la pianificazione.
  • Un processo è un insieme di risorse condivise. Ciò significa che è costituito da una parte di memoria, variabili, istanze di oggetti, handle di file, mutex, connessioni al database e così via. Ogni processo contiene anche uno o più thread. Tutti i thread dello stesso processo condividono le sue risorse, quindi puoi usare una variabile in un thread che hai creato in un altro. Se quei thread fanno parte di due processi diversi, non possono accedere direttamente alle risorse degli altri. In questo caso è necessaria la comunicazione tra processi attraverso, ad esempio, pipe, file, socket ...

multiprocessing

Puoi ottenere il calcolo parallelo creando nuovi processi (che contengono anche un nuovo thread) con php. Se i tuoi thread non richiedono molta comunicazione o sincronizzazione, questa è la tua scelta, poiché i processi sono isolati e non possono interferire con il lavoro reciproco. Anche se uno si blocca, ciò non riguarda gli altri. Se hai bisogno di molte comunicazioni, dovresti leggere sul "multithreading" o - purtroppo - prendere in considerazione l'uso di un altro linguaggio di programmazione, perché la comunicazione e la sincronizzazione tra processi introducono molta carnagione.

In php hai due modi per creare un nuovo processo:

lascia che il sistema operativo lo faccia per te : puoi dire al tuo sistema operativo di creare un nuovo processo ed eseguire un nuovo (o lo stesso) script php al suo interno.

  • per Linux puoi usare quanto segue o considerare la risposta di Darryl Hein :

    $cmd = 'nice php script.php 2>&1 & echo $!';
    pclose(popen($cmd, 'r'));
  • per Windows puoi usare questo:

    $cmd = 'start "processname" /MIN /belownormal cmd /c "script.php 2>&1"';
    pclose(popen($cmd, 'r'));

fai da te con un fork : php offre anche la possibilità di usare il fork attraverso la funzione pcntl_fork () . Un buon tutorial su come farlo può essere trovato qui, ma consiglio vivamente di non usarlo, dal momento che fork è un crimine contro l'umanità e soprattutto contro l'oop.

multithreading

Con il multithreading tutti i tuoi thread condividono le loro risorse in modo da poter comunicare facilmente tra loro e sincronizzarle senza sovraccarico. Dall'altro lato devi sapere cosa stai facendo, poiché le condizioni di gara e gli deadlock sono facili da produrre ma molto difficili da eseguire il debug.

Il php standard non fornisce alcun multithreading ma esiste un'estensione (sperimentale) che in realtà lo fa - pthreads . La sua documentazione API ha persino trasformato in php.net . Con esso puoi fare alcune cose come puoi nei veri linguaggi di programmazione :-) in questo modo:

class MyThread extends Thread {
    public function run(){
        //do something time consuming
    }
}

$t = new MyThread();
if($t->start()){
    while($t->isRunning()){
        echo ".";
        usleep(100);
    }
    $t->join();
}

Per Linux c'è una guida all'installazione proprio qui da StackOverflow.

Per Windows ce n'è uno ora:

  • Per prima cosa hai bisogno della versione thread-safe di php.
  • Hai bisogno delle versioni precompilate di entrambi pthreads e della sua estensione php. Possono essere scaricati qui . Assicurati di scaricare la versione compatibile con la tua versione php.
  • Copia php_pthreads.dll (dallo zip appena scaricato) nella cartella dell'estensione php ([phpDirectory] / ext).
  • Copia pthreadVC2.dll in [phpDirectory] (la cartella principale, non la cartella delle estensioni).
  • Modifica [phpDirectory] /php.ini e inserisci la seguente riga

    extension=php_pthreads.dll
  • Provalo con lo script sopra con un po 'di sonno o qualcosa proprio lì dove si trova il commento.

E ora il grande MA : sebbene funzioni davvero, php non era originariamente creato per il multithreading. Esiste una versione thread-safe di php e dalla v5.4 sembra quasi priva di bug ma l'utilizzo di php in un ambiente multi-thread è ancora scoraggiato nel manuale di php (ma forse non hanno appena aggiornato il loro manuale su questo, ancora). Un problema molto più grande potrebbe essere che molte estensioni comuni non sono thread-safe . Quindi potresti ottenere thread con questa estensione php ma le funzioni da cui dipendi non sono ancora thread-safe, quindi probabilmente incontrerai condizioni di gara, deadlock e così via nel codice che non hai scritto tu stesso ...


5
Questo è terribilmente sbagliato, l'articolo a cui hai fatto riferimento è del 2008. Se PHP non fosse stato thread-safe nel core non avrebbe thread thread SAPI.
Joe Watkins,

1
@Joe: Va bene, l'ho cambiato in core è thread-safe, ma molte estensioni no.
Francois Bourgeois,

1
Molte ? Penso che troverai pochissimi, hai trovato la documentazione ma non hai letto correttamente: Nota: quelli contrassegnati con * non sono librerie thread-safe e non dovrebbero essere usati con PHP come modulo server nel multi server Web Windows (IIS, Netscape). Questo non ha ancora importanza negli ambienti Unix.
Joe Watkins,

6
PHP è molto sicuro, ed è stato per molti anni, alcune delle librerie esterne e un paio di librerie raggruppate non lo sono, ma è ben documentato e comunque abbastanza ovvio. pthreads crea thread sicuri come i thread creati da Zend in un sapi multi-thread, lo so, perché io, da solo, ho scritto pthreads. Utilizza tutte le API disponibili esposte da PHP proprio come fanno le API del server, non sto dicendo che sia completamente stabile, ma l'immagine che hai dipinto è semplicemente sbagliata e molto scarsamente informata.
Joe Watkins,

@Joe: quando il manuale dice che questo non ha importanza per gli ambienti Unix, si riferiscono al fatto che sul sistema Unix apache utilizza più processi e su Windows utilizza thread. Quindi, in pratica, stanno dicendo "se non usi i thread, non devi preoccuparti delle estensioni non thread-safe". Quando usiamo thread con pthreads, ovviamente - importa anche in ambienti Unix.
Francois Bourgeois,

17

Puoi usare pcntl_fork () per ottenere qualcosa di simile ai thread. Tecnicamente si tratta di processi separati, quindi la comunicazione tra i due non è così semplice con i thread, e credo che non funzionerà se PHP viene chiamato da Apache.


4
Sto usando con successo pcntl_fork per parallelizzare un'attività di importazione di dati piuttosto massiccia. Funziona benissimo e l'ho fatto funzionare in circa un'ora. C'è un po 'di una curva di apprendimento, ma una volta capito cosa sta succedendo, è piuttosto semplice.
Frank Farmer,

Frank, è con CLI php o apache PHP?
Artem Russakovskii,

@Artem: anche io vorrei saperlo.
Josh K,

5
@Frank Farmer ci sta prendendo in giro ... proprio come il pacchetto PECL.
Roger,

1
Stavo usando pcntl_fork con CLI. Non l'ho mai provato in apache; sembra rischioso. Anche sulla CLI, c'erano alcuni problemi imprevisti. Mi sembrava di avere un problema in cui se un bambino chiudesse un handle di database (perché aveva finito il suo lavoro), avrebbe chiuso anche la connessione per i fratelli. Poiché i bambini sono copie del genitore, prepararsi alla stranezza. Da allora ho riprogettato il mio codice per generare semplicemente nuovi processi completamente separati tramite exec () - è più pulito in quel modo.
Frank Farmer,


7

pcntl_fork()è quello che stai cercando, ma il suo processo di fork non è il threading. quindi avrai il problema dello scambio di dati. per risolverli è possibile utilizzare le funzioni dei semafori phps ( http://www.php.net/manual/de/ref.sem.php ) le code dei messaggi potrebbero essere un po 'più semplici all'inizio rispetto ai segmenti di memoria condivisa.

Comunque, una strategia che sto usando in un framework web che sto sviluppando che carica blocchi ad alta intensità di risorse di una pagina web (probabilmente con richieste esterne) parallela: sto facendo una fila di lavoro per sapere quali dati sto aspettando e poi faccio fork fuori dai lavori per ogni processo. una volta fatto memorizzano i loro dati nella cache apc in una chiave univoca a cui il processo genitore può accedere. una volta che ogni dato è lì, continua. sto usando un sempliceusleep() l'attesa perché la comunicazione tra processi non è possibile in apache (i bambini perderanno la connessione con i loro genitori e diventeranno zombi ...). quindi questo mi porta all'ultima cosa: è importante uccidere se stessi ogni bambino! ci sono anche classi che eseguono il fork dei processi ma mantengono i dati, non li ho esaminati ma il framework zend ne ha uno e di solito eseguono un codice lento ma affidabile. Potete trovare qui: http://zendframework.com/manual/1.9/en/zendx.console.process.unix.overview.html penso che usano i segmenti shm! beh, ultimo ma non meno importante, c'è un errore su questo sito Web zend, un piccolo errore nell'esempio.

while ($process1->isRunning() && $process2->isRunning()) {
    sleep(1);
}
should of course be:
while ($process1->isRunning() || $process2->isRunning()) {
    sleep(1);
}



5

Ho una classe di threading PHP che funziona perfettamente in un ambiente di produzione da oltre due anni.

EDIT: Questo è ora disponibile come libreria per compositori e come parte del mio framework MVC, Hazaar MVC.

Vedi: https://git.hazaarlabs.com/hazaar/hazaar-thread


Che cosa succede se, seguendo il tuo esempio, il programma in file.php, diciamo ad esempio, rafforza l'esistenza di un elenco di uris del sito Web 10k e quindi deve salvare il risultato in un file CSV ... La scrittura di questo file sarebbe un problema?
Roger,

Il processo secondario verrà eseguito come lo stesso utente dello script web-server / parent. Quindi, quando scrivi i file avrai le stesse considerazioni riguardo alle autorizzazioni come faresti normalmente. Se hai problemi a scrivere file, prova a scrivere su / tmp e quando funziona, vai da lì.
Jamie Carl,

1
Il link ora è morto a causa di una riprogettazione, puoi trovarlo sulla macchina del ritorno qui: web.archive.org/web/20130922043615/http://dev.funkynerd.com/…
Tony

Aggiunto al mio framework MVC ora. Vedi: git.hazaarlabs.com/hazaar/hazaar-thread
Jamie Carl


1

Hai mai sentito parlare appserverdi techdivision?

È scritto in php e funziona come un appserver che gestisce i multithread per applicazioni php ad alto traffico. È ancora in beta ma molto promettente.


-3

C'è la caratteristica piuttosto oscura, e presto da deprecare, chiamata tick . L'unica cosa per cui l'ho mai usato è consentire a uno script di catturare SIGKILL (Ctrl + C) e chiuderlo con grazia.


3
Le zecche non vengono eseguite in parallelo. In sostanza, dopo ogni istruzione, viene eseguita la funzione tick. Mentre la funzione tick è in esecuzione, il codice principale non è in esecuzione.
Frank Farmer,

1
i tick sono necessari solo per l'handler signal ().
Nick,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.