Perché le fibre non possono utilizzare più processori?


8

Sembra che la distinzione tra fibre e fili sia che le fibre sono programmate in modo cooperativo, mentre i fili sono programmati preventivamente. Il punto dello scheduler sembra un modo per far funzionare una risorsa di processore altrimenti seriale in modo parallelo, "condividendo il tempo" della CPU. Tuttavia, su un processore dual-core con ogni core che esegue il proprio thread, suppongo che non sia necessario sospendere l'esecuzione di un thread perché l'altro continui perché non "condividono il tempo" un singolo processore.

Quindi, se la differenza tra thread e fibre è il modo in cui vengono interrotti dallo scheduler e l'interruzione non è necessaria quando si esegue su core fisicamente separati, perché le fibre non possono sfruttare più core del processore quando i thread possono?

Fonti di confusione:

.. principalmente Wikipedia

  1. http://en.wikipedia.org/wiki/Fiber_%28computer_science%29

    Uno svantaggio è che le fibre non possono utilizzare macchine multiprocessore senza utilizzare anche filettature preventive

  2. http://en.wikipedia.org/wiki/Computer_multitasking#Multithreading

    ... [fibre] tendono a perdere alcuni o tutti i vantaggi dei thread su macchine con processori multipli.

Risposte:


9

La principale distinzione, come fai notare nella tua domanda, è se lo scheduler prevarrà o meno un thread. Il modo in cui un programmatore pensa alla condivisione di strutture di dati o alla sincronizzazione tra "thread" è molto diverso nei sistemi preventivi e cooperativi.

In un sistema cooperativo (che va da molti nomi, cooperative multitasking , nonpreemptive multitasking , thread a livello utente , fili verdi , e le fibre sono cinque quelli comuni attualmente) il programmatore è garantito che il loro codice verrà eseguito atomicamente finché non effettuano chiamate di sistema o chiamate yield(). Ciò rende particolarmente facile gestire le strutture dati condivise tra più fibre. A meno che non sia necessario effettuare una chiamata di sistema come parte di una sezione critica, non è necessario contrassegnare le sezioni critiche ( ad esempio con mutex locke unlockchiamate). Quindi in codice come:

x = x + y
y = 2 * x

il programmatore non deve preoccuparsi che qualche altra fibra possa lavorare contemporaneamente con le variabili xe y. xe yverrà aggiornato atomicamente insieme dal punto di vista di tutte le altre fibre. Allo stesso modo, tutte le fibre potrebbero condividere una struttura più complicata, come un albero e una chiamata come tree.insert(key, value)non dovrebbe essere protetta da alcun mutex o sezione critica.

Al contrario, in un sistema multithreading preventivo, come con thread realmente paralleli / multicore, è possibile ogni possibile interlacciamento di istruzioni tra thread a meno che non vi siano sezioni critiche esplicite. Un'interruzione e una prelazione potrebbero diventare tra due istruzioni qualsiasi. Nell'esempio sopra:

 thread 0                thread 1
                         < thread 1 could read or modify x or y at this point
 read x
                         < thread 1 could read or modify x or y at this point
 read y
                         < thread 1 could read or modify x or y at this point
 add x and y
                         < thread 1 could read or modify x or y at this point
 write the result back into x
                         < thread 1 could read or modify x or y at this point
 read x
                         < thread 1 could read or modify x or y at this point
 multiply by 2
                         < thread 1 could read or modify x or y at this point
 write the result back into y
                         < thread 1 could read or modify x or y at this point

Quindi, per essere corretti su un sistema preventivo, o su un sistema con thread veramente paralleli, è necessario circondare ogni sezione critica con una sorta di sincronizzazione, come un mutex lockall'inizio e un mutex unlockalla fine.

Le fibre sono quindi più simili alle librerie di I / O asincrone che ai thread preventivi o ai thread veramente paralleli. Lo scheduler delle fibre viene richiamato e può cambiare fibra durante le operazioni di I / O a lunga latenza. Ciò può offrire il vantaggio di più operazioni di I / O simultanee senza richiedere operazioni di sincronizzazione in sezioni critiche. Pertanto, l'uso delle fibre può forse avere una minore complessità di programmazione rispetto ai thread preventivi o veramente paralleli, ma la mancanza di sincronizzazione attorno alle sezioni critiche porterebbe a risultati disastrosi se si provasse a far funzionare le fibre in modo simultaneo o preventivo.


Penso che si debba probabilmente fare menzione di 1. sistemi ibridi in cui il sistema di thread a livello di utente si occupa di distribuire (molti) thread a livello di utente su (pochi) core della CPU e 2. il fatto che durante la programmazione su "bare metal" , è possibile ottenere il multiprocessing senza prelazione.
dfeuer

1
@dfeuer Non credo che la domanda stia ponendo tutti i diversi modi possibili per trarre vantaggio dal multiprocessing. La domanda mentre la leggo è "perché le fibre (note anche come attività non preventive) non possono essere trattate come fili preventivi?" Se stai assumendo un vero parallelismo, allora devi sincronizzare correttamente, quindi non hai più "fibre".
Wandering Logic,

1
Bella risposta. Le fibre non possono garantire la sicurezza perché il programma presuppone che abbia accesso esclusivo alle risorse condivise fino a quando non specifica un punto di interruzione, in cui i thread presuppongono che un accesso / mutazione possa essere effettuato in qualsiasi momento; ovviamente il presupposto più sicuro quando più nodi realmente paralleli interagiscono con gli stessi dati.
James M. Lay

6

La risposta è in realtà che potrebbero, ma c'è il desiderio di non farlo.

Le fibre vengono utilizzate perché consentono di controllare la modalità di pianificazione. Di conseguenza, è molto più semplice progettare alcuni algoritmi usando le fibre perché il programmatore dice in quale fibra viene eseguita in qualsiasi momento. Tuttavia, se si desidera eseguire due fibre contemporaneamente su due core diversi, è necessario pianificarle manualmente per farlo.

I thread danno il controllo di quale codice viene eseguito sul sistema operativo. In cambio, il sistema operativo si occupa di molte brutte attività per te. Alcuni algoritmi diventano più difficili, perché il programmatore ha meno voce in capitolo su quale codice viene eseguito in un determinato momento, quindi possono emergere casi più imprevisti. Strumenti come mutex e semafori vengono aggiunti a un sistema operativo per fornire al programmatore il controllo sufficiente per rendere utili i thread e ridurre alcune delle incertezze, senza rallentare il programmatore.

Ciò porta a qualcosa di ancora più importante della cooperazione rispetto alla prevenzione: le fibre sono controllate dal programmatore, mentre i thread sono controllati dal sistema operativo.

Non devi spawnare una fibra su un altro processore. I comandi a livello di assembly per farlo sono atrocemente complicati e spesso sono specifici del processore. Non è necessario scrivere 15 diverse versioni del codice per gestire questi processori, quindi si passa al sistema operativo. Il compito del sistema operativo è di eliminare queste differenze. Il risultato è "discussioni".

Le fibre corrono sopra i fili. Non corrono da soli. Di conseguenza, se vuoi far passare due fibre su nuclei diversi, puoi semplicemente generare due fili ed eseguire una fibra su ciascuno di essi. In molte implementazioni di fibre, puoi farlo facilmente. Il supporto multi-core non proviene dalle fibre, ma dai fili.

Diventa facile dimostrare che, a meno che tu non voglia scrivere il tuo codice specifico del processore, non c'è niente che potresti fare assegnando fibre a più core che non potresti fare creando fili e assegnando fibre a ciascuno. Una delle mie regole preferite per la progettazione di API è "Un'API non viene eseguita quando hai finito di aggiungere tutto, ma piuttosto quando non riesci più a trovare altro da eliminare". Dato che il multi-core è gestito perfettamente ospitando le fibre sui thread, non c'è motivo di complicare l'API della fibra aggiungendo multi-core a quel livello.

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.