In primo luogo, la tua domanda sembra confusa sulla relazione tra un GIL e il multithreading cooperativo. Il multithreading cooperativo è quando il thread corrente continua ad essere eseguito fino a quando non si arrende. La libreria di greenlet per python si basa su questo modello. Semplifica la codifica in molti casi perché non ti devi preoccupare degli switch di contesto tranne che in punti specifici.
Un blocco dell'interprete globale è un blocco che impedisce a più thread di eseguire codice all'interno della macchina virtuale contemporaneamente. L'esecuzione salterà comunque da una discussione all'altra senza che il thread la richieda. I tempi in cui gli switch avverranno sono limitati (esattamente come dipende dall'implementazione del linguaggio). Ma non sei proprio la semplificazione che ti offre il multitasking cooperativo.
La tua domanda sembra in realtà chiedere se puoi cavartela con il multitasking cooperativo con opzioni multi-processo. Ovviamente parlando in modo rigoroso puoi ancora fare tutto ciò che vuoi senza il pre-utilizzo del multithreading, la domanda è se sarà più facile / più efficiente con esso.
Uso il multithreading cooperativo e parallelamente elabora la parallelizzazione dei processi. Il più delle volte trovo che funzioni magnificamente e sia un approccio più semplice di quello che sarebbe necessario se dovessi provare a usare i thread. Ma penso che ci siano alcuni casi in cui questo cade.
Consideriamo alcuni esempi:
1) Thread del lavoratore e thread dell'interfaccia utente
Non è raro avere un'attività a lunga esecuzione eseguita in un'applicazione mentre viene visualizzata una barra di avanzamento. Al fine di mantenere le cose funzionanti abbiamo bisogno di eseguire eventi UI e continuare a eseguire l'attività. Normalmente, dovremmo eseguire l'attività in un thread separato. Ma se i thread sono cooperativi, questo non funzionerà perché l'attività normalmente non avrà alcun motivo per ritardare se stessa.
Quindi cosa possiamo fare?
- In alcuni casi, ci sono stati punti di pausa naturali nel task di lunga durata. Possono esserci file I / O, chiamate database, letture socket. Tutti questi naturalmente bloccano, e se la tua lingua automaticamente filtra le attese in questi punti, molte attività di lunga durata possono produrre naturalmente.
- L'attività potrebbe essere spostata in un altro processo. Ma per alcuni compiti, ci vorrà un grande sforzo. Potrei dover spedire molti dati al sottoprocesso e quindi lasciarlo elaborare e spedire i dati.
- Potresti introdurre chiamate esplicite sul rendimento del thread. Lo svantaggio qui è che stai facendo qualcosa manualmente che gli altri linguaggi fanno automaticamente.
2) Serve molte richieste
Un sistema come un database o un server web potrebbe dover servire richieste provenienti da diversi sistemi esterni. In tal modo dovrà navigare all'interno delle strutture di dati in memoria e più richieste potrebbero richiedere le stesse strutture di dati. In genere, è possibile implementarlo utilizzando più thread e utilizzando i blocchi sulla struttura dati per assicurarsi che nessuno lo cambi mentre viene letto.
Finché abbiamo solo un core operativo, il multithreading cooperativo funziona davvero alla grande. Ma quando hai più core, non puoi approfittarne in questo modo. Potresti introdurre più processi. Ma il problema è che non si può davvero condividere le strutture dei dati in memoria così bene. Sono sicuro che puoi aggirarlo con le tecniche IPC, ma penso che sarà sempre imbarazzante rispetto al modello di serrature.