In Ruby, questo codice non è threadsafe se array
viene modificato da tanti fili:Perché l'operazione << su un array in Ruby non è atomica?
array = []
array << :foo # many threads can run this code
Perché l'operazione <<
non thread-safe?
In Ruby, questo codice non è threadsafe se array
viene modificato da tanti fili:Perché l'operazione << su un array in Ruby non è atomica?
array = []
array << :foo # many threads can run this code
Perché l'operazione <<
non thread-safe?
array
è la variabile del programma quando si applica un'operazione come <<
ad esso. Succede in tre passi:
Quindi questa operazione singola di alto livello viene eseguita in tre passaggi. Tra questi passaggi, a causa della commutazione del contesto dei thread, altri thread potrebbero leggere lo stesso valore (vecchio) della variabile. Ecco perché non è un'operazione atomica.
Questo link potrebbe essere utile per voi:
http://www.jstorimer.com/pages/ruby-core-classes-arent-thread-safe
Inoltre si potrebbero essere interessati a questo gioiello:
Perché Ruby è un linguaggio di livello molto alto, niente è davvero atomico a livello di sistema operativo. Solo operazioni di assemblaggio molto semplici sono atomiche a livello di SO (dipende dal sistema operativo) e ogni operazione Ruby, anche una semplice 1 + 1
corrisponde a centinaia o migliaia di istruzioni di assemblaggio eseguite, come ricerche di metodi, garbage collection, inizializzazione di oggetti, calcoli di scope, ecc.
Se è necessario eseguire operazioni atomiche, utilizzare Mutex.
Se più thread accedono allo stesso array, utilizzare la classe integrata di Ruby Queue. Gestisce bene produttori e consumatori.
Questo è l'esempio dalla documentazione:
require 'thread'
queue = Queue.new
producer = Thread.new do
5.times do |i|
sleep rand(i) # simulate expense
queue << i
puts "#{i} produced"
end
end
consumer = Thread.new do
5.times do |i|
value = queue.pop
sleep rand(i/2) # simulate expense
puts "consumed #{value}"
end
end
consumer.join
realtà usando la risonanza magnetica (implementazione Ruby Matz) GIL (Global Interpreter Lock) fa alcuna C-pura funzione atomica.
Poiché Array#<<
è implementato come codice C puro in MRI, questa operazione sarà atomica. Ma nota questo si applica solo alla risonanza magnetica. Su JRuby questo non è il caso.
di comprendere a fondo ciò che sta accadendo vi consiglio di leggere questi due articoli, che spiega tutto molto bene:
Nobody Understands the GIL
Nobody Understands the GIL - part 2
Proprio riffing off di @Linuxios e @TheTinMan: di alto livello le operazioni di linguaggio (HLL) in generale non sono atomiche. L'atomicità è (generalmente) non un problema nei programmi a thread singolo.Nei programmi multi-threaded, tu (il programmatore) devi ragionare su una granularità molto più alta di una singola operazione HLL, quindi avere le singole operazioni HLL che sono atomiche in realtà non ti aiuta molto. Il rovescio della medaglia, anche se fare un'operazione atomica richiede solo poche istruzioni prima e dopo lo — almeno sull'hardware moderno — sommate le spese generali statiche (dimensione binaria) e dinamiche (tempo di esecuzione). Ancor peggio, l'atomicità esplicita disabilita praticamente tutta l'ottimizzazione perché i compilatori non possono spostare le istruzioni attraverso le operazioni atomiche. Nessun vantaggio reale + costo significativo = non-starter.
potresti leggere: [** Operazioni atomiche in Ruby **] (http://moonbase.rydia.net/mental/blog/programming/atomic-operations-in-ruby.html) –
hai letto Questo? [Aggiornato con il commento di Jörg su Sept 2011] (http://stackoverflow.com/questions/56087/does-ruby-have-real-multithreading/57802#57802) –
@ theTinMan Un sacco di ringraziamenti! il mio inglese è scarso :(ma noto attentamente la tua e precedente modifica alla mia risposta migliorerò nella prossima risposta Grazie! –