GVL förklarad
Varför trådar är begränsade.
GVL förklarad är en gratis lektion i Ruby Academy på CoddyKit. Detta är lektion 2 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Ruby Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Ruby Academy innehåller totalt 4 lektioner.
Vad är GVL?
GVL (Global VM Lock, historiskt GIL) är ett lås inuti CRuby, den vanliga Ruby-tolken.
- Det tillåter endast en tråd att köra Ruby-kod åt gången.
- Det skyddar tolkens interna delar mot samtidig korruption.
- Det innebär att CPU-arbete i ren Ruby inte verkligen körs parallellt på flera kärnor.
Genom att förstå GVL blir det tydligt när trådar hjälper och när de inte gör det.
Varför det finns
CRubys interna delar (objektallokering, skräpsamling och C-tillägg) skrevs inte alla för att vara trådsäkra. GVL gör dem säkra genom att serialisera Ruby-körningen.
Det är svårt att ta bort GVL på ett robust sätt, så CRuby behåller det. JRuby och TruffleRuby har inget GVL och kan köra trådar på många kärnor.
CPU-bundet arbete
För CPU-bundna uppgifter (matematik, sortering och tolkning) gör trådar inte arbetet snabbare i CRuby. Bara en tråd åt gången kör Ruby-kod, så två CPU-trådar motsvarar ungefär en tråd plus extra kostnader.
def heavy
sum = 0
1_000_00.times { |i| sum += i }
sum
end
puts heavy
puts "CPU work does not parallelize under the GVL"I/O frigör GVL
Den viktiga insikten är att blockerande I/O frigör GVL. När en tråd sover, läser en fil eller väntar på ett uttag släpper den låset, så att en annan tråd kan köra Ruby-kod.
Därför är trådar utmärkta för I/O-bundet arbete även med GVL.
Överlappande väntetider
Här sover tre trådar. Eftersom sleep frigör GVL överlappar väntetiderna varandra. Den totala tiden är ungefär 0,2 sekunder, inte 0,6 sekunder.
start = Time.now
threads = (1..3).map do
Thread.new { sleep 0.2 }
end
threads.each(&:join)
elapsed = Time.now - start
puts "Elapsed roughly: " + elapsed.round(1).to_sC-tillägg kan frigöra det
Välskrivna C-tillägg kan frigöra GVL under långa beräkningar i inbyggd kod med hjälp av rb_thread_call_without_gvl. Det gör att tungt arbete i inbyggd kod kan köras parallellt medan Ruby-trådar fortsätter.
På så sätt kan vissa bibliotek uppnå verklig parallellism även i CRuby.
Trådar växlar ändå
Även vid CPU-arbete fryser GVL inte andra trådar för alltid. CRuby avbryter en tråd med jämna mellanrum så att alla får sin tur. Arbetet är samtidigt (interfolierat), men inte parallellt (samtidigt på riktigt).
results = []
mutex = Mutex.new
threads = (1..3).map do |n|
Thread.new do
mutex.synchronize { results << n }
end
end
threads.each(&:join)
puts "Collected: " + results.sort.join(", ")Samtidighet kontra parallellism
Två viktiga begrepp:
- Samtidighet: uppgifter gör framsteg genom att växla mellan varandra. GVL tillåter detta.
- Parallellism: uppgifter körs exakt samtidigt på olika kärnor. GVL förhindrar detta för Ruby-kod.
Trådar ger dig samtidighet; Ractors ger dig parallellism.
Runt GVL
Om du vill använda flera kärnor för CPU-arbete i CRuby kan du:
- Köra flera processer (var och en har sitt eget GVL).
- Använda Ractors för parallellism i samma process.
- Flytta arbetet till C-tillägg som frigör GVL.
För I/O-arbete räcker vanliga trådar oftast.
Processer har inget gemensamt GVL
Varje operativsystemsprocess kör sin egen Ruby-VM med sitt eget GVL. Att skapa processer genom fork ger verklig parallellism, men processer delar inte minne och använder mer resurser.
puts "Main pid: " + Process.pid.to_s
puts "Each forked process has its own independent GVL"Välja strategi
Vägledning för valet:
- Mycket väntan? Använd trådar.
- Tungt CPU-arbete och behov av flera kärnor? Använd processer eller Ractors.
- Behöver du delat tillstånd? Använd trådar med en
Mutex, men tänk på GVL:s begränsningar.
Genom att känna till GVL undviker du det klassiska misstaget att förvänta dig linjär skalning med CPU-trådar.
Snabbtest
Testa dina kunskaper om GVL.
Sammanfattning: GVL
Viktiga slutsatser om Global VM Lock:
- Bara en tråd åt gången kör Ruby-kod i CRuby.
- Det skyddar tolkens interna delar.
- Blockerande I/O frigör det, vilket möjliggör överlappande väntetider.
- CPU-bundet Ruby-arbete parallelliseras inte över flera kärnor.
- Använd processer eller Ractors för verklig parallellism.
Härnäst tittar vi på fibrer för lättviktig kooperativ samtidighet.
Lär dig Ruby med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 29
- Lektioner
- 109
Vanliga frågor
Är lektionen ”GVL förklarad” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Ruby Academy, inklusive ”GVL förklarad”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Ruby Academy innehåller totalt 4 lektioner.
Vad lär jag mig i ”GVL förklarad”?
Varför trådar är begränsade. Ni övar på Ruby Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Ruby Academy?
Du behöver inga förkunskaper. Utbildningen i Ruby Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.
Hur lång tid tar lektionen ”GVL förklarad”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Ruby Academy-lektionen?
Ja. Varje Ruby Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.