CPython'daki global tercüman kilidi (GIL) nedir?


244

Küresel bir tercüman kilidi nedir ve neden bir sorundur?

GIL'in Python'dan kaldırılması konusunda çok fazla gürültü yapıldı ve bunun neden bu kadar önemli olduğunu anlamak istiyorum. Hiçbir zaman bir derleyici veya tercüman yazmadım, bu yüzden ayrıntılarla tutumlu olmayın, muhtemelen anlamaları gerekir.


3
David Beazley'in size GIL hakkında bilmek istediğiniz her şeyi anlatmasını izleyin .
hughdbrown

1
İşte bir süre önce yazdığım Python'daki GIL ve iplik hakkında uzunca bir makale. Üzerinde adil bir ayrıntı var: jessenoller.com/2009/02/01/…
jnoller


3
Bunun GIL'in en iyi açıklaması olduğunu düşünüyorum. Lütfen oku. dabeaz.com/python/AnderstandingGIL.pdf
suhao399

realpython.com/python-gil Bunu yararlı buldum
qwr

Yanıtlar:


220

Python'un GIL'i farklı dizilerden tercüman içlerine erişimi serileştirmeyi amaçlamaktadır. Çok çekirdekli sistemlerde, birden çok iş parçacığının birden çok çekirdeği etkin bir şekilde kullanamayacağı anlamına gelir. (GIL bu soruna yol açmadıysa, çoğu insan GIL'i umursamaz - sadece çok çekirdekli sistemlerin yaygınlığının artması nedeniyle bir sorun olarak gündeme getirilir.) Ayrıntılı olarak anlamak istiyorsanız, bu videoyu izleyebilir veya bu slayt grubuna bakabilirsiniz . Çok fazla bilgi olabilir, ama sonra bilgi istediniz :-)

Python'un GIL'inin sadece referans uygulama olan CPython için bir sorun olduğunu unutmayın. Jython ve IronPython'un GIL'si yoktur. Bir Python geliştiricisi olarak, bir C uzantısı yazmazsanız genellikle GIL ile karşılaşmazsınız. C uzantısı yazarları, uzantıları G / Ç'yi engellediğinde GIL'i serbest bırakmalıdır, böylece Python işlemindeki diğer iş parçacıklarının çalışma şansı elde eder.


46
İyi cevap - temel olarak Python'daki dişlerin sadece G / Ç'yi engellemek için iyi olduğu anlamına gelir; uygulamanız asla işlemci kullanımının 1 CPU çekirdeğinin üzerine çıkmayacak
Ana Betts

8
"Bir Python geliştiricisi olarak, bir C uzantısı yazmadığınız sürece genellikle GIL ile karşılaşmazsınız" - Bir salyangoz hızında çalışan çok iş parçacıklı kodunuzun nedeninin GIL olduğunu bilmiyor olabilirsiniz, ancak Etkilerini kesinlikle hissedeceğim. Python ile 32 çekirdekli bir sunucudan yararlanmak, ilgili tüm ek yüke sahip 32 işleme ihtiyacım olduğu anlamına geliyor.
Temel

6
@PaulBetts: bu doğru değil. Bu performans kritik kodu zaten ve GIL örneğin serbest yapabilirim C uzantılarını kullanır olasıdır regex, lxml, numpymodüller. Cython özel kod GIL serbest bırakmak için izin verir, örneğin,b2a_bin(data)
jfs

5
@Paul Betts: Çok işlem modülünü kullanarak işlemci kullanımının 1'den fazla CPU kodunu alabilirsiniz . Birden çok işlem oluşturmak, birden çok iş parçacığı oluşturmaktan "daha ağırdır", ancak gerçekten paralel olarak, python'da iş yapmanız gerekiyorsa, bu bir seçenektir.
AJNeufeld

1
@david_adler Evet, hala geçerli ve bir süre daha böyle kalacak. Bu, Python'un birçok farklı iş yükü için gerçekten yararlı olmasını gerçekten durdurmadı.
Vinay Sajip

59

Birbirinizin verilerine gerçekten dokunmayan birden fazla iş parçacığınız olduğunu varsayalım . Bunlar mümkün olduğu kadar bağımsız yürütülmelidir. Bir işlevi çağırmak (demek) için almanız gereken bir "genel kilit" varsa, bu da bir darboğaz olarak ortaya çıkabilir. İlk etapta birden fazla iş parçacığına sahip olmaktan çok fazla faydalanmamanızı sağlayabilirsiniz.

Gerçek bir dünya benzetmesine koymak için: sadece bir kahve kupasına sahip bir şirkette çalışan 100 geliştiriciyi hayal edin. Geliştiricilerin çoğu zamanlarını kodlama yerine kahve bekleyerek geçiriyorlardı.

Bunların hiçbiri Python'a özgü değildir - Python'un ilk olarak bir GIL için neye ihtiyacı olduğunu bilmiyorum. Ancak, umarım size genel konsept hakkında daha iyi bir fikir verilir.


Kahve kupasını beklemek dışında, kupayı beklerken kesinlikle başka şeyler yapabildikleri için oldukça G / Ç bağlı bir süreç gibi görünüyor. GIL, zamanlarının çoğunu beklemek için harcayan I / O ağır dişleri üzerinde çok az etkiye sahiptir.
Cruncher


36

İlk önce Python GIL'in neler sunduğunu anlayalım:

Herhangi bir işlem / komut yorumlayıcıda yürütülür. GIL, tercümanın belirli bir anda tek bir iş parçacığı tarafından tutulmasını sağlar . Ve birden çok iş parçacığı içeren python programınız tek bir yorumlayıcıda çalışır. Herhangi bir zamanda, bu yorumlayıcı tek bir iş parçacığı tarafından tutulur. Bu tercüman tutuyor sadece iplik anlamına gelir çalıştıran de zamanın herhangi bir anda .

Şimdi bu neden bir sorun:

Makinenizde birden fazla çekirdek / işlemci olabilir. Birden çok iş parçacığı aynı anda birden çok iş parçacığının yürütülmesine izin verir. herhangi bir zamanda çalıştırılabilir. . Ancak yorumlayıcı tek bir iş parçacığı tarafından tutulduğundan, diğer iş parçacıkları bir çekirdeğe erişmelerine rağmen hiçbir şey yapmazlar. Bu nedenle, birden fazla çekirdek tarafından herhangi bir avantaj elde edemezsiniz, çünkü herhangi bir anda, yorumlayıcıyı elinde tutan iplik tarafından kullanılan çekirdek olan tek bir çekirdek kullanılır. Bu nedenle, programınızın yürütülmesi, tek iş parçacıklı bir programmış gibi çalışacaktır.

Bununla birlikte, G / Ç, görüntü işleme ve NumPy sayısı çatlaması gibi potansiyel olarak engelleme veya uzun süren işlemler GIL dışında gerçekleşir. Buradan alındı . Bu tür işlemler için, GIL varlığına rağmen, çok iş parçacıklı bir işlem tek bir dişli işlemden daha hızlı olacaktır. Yani, GIL her zaman bir darboğaz değildir.

Düzenleme: GIL CPython bir uygulama detayıdır. IronPython ve Jython'un GIL'i yoktur, bu yüzden PyPy ve Jython'u hiç kullanmadığımı ve bundan emin olmadığımı düşündükleri için gerçekten çok iş parçacıklı bir program mümkün olmalıdır.


4
Not : PyPy vardır GIL . Referans : http://doc.pypy.org/tr/latest/faq.html#does-pypy-have-a-gil-why . Ironpython ve Jython'un GIL'i yokken.
Tasdik Rahman

Gerçekten, PyPy'nin bir GIL'si vardır, ancak IronPython yoktur.
Emmanuel

@Emmanuel PyPy'yi kaldırmak ve IronPython'u dahil etmek için cevabı düzenledi.
Akshar Raaj

17

Python, kelimenin tam anlamıyla çoklu iş parçacığına izin vermez. Çok iş parçacıklı bir paketi var, ancak kodunuzu hızlandırmak için çok iş parçacıklı bir paket istiyorsanız, bunu kullanmak genellikle iyi bir fikir değildir. Python'un Global Tercüman Kilidi (GIL) adı verilen bir yapısı vardır.

https://www.youtube.com/watch?v=ph374fJqFPE

GIL, 'iş parçacıklarınızdan' yalnızca bir tanesinin aynı anda çalışabilmesini sağlar. Bir iş parçacığı GIL'i alır, küçük bir iş yapar, sonra GIL'i bir sonraki iş parçacığına geçirir. Bu çok hızlı bir şekilde gerçekleşir, böylece insan gözü için iplikleriniz paralel olarak çalışıyor gibi görünebilir, ancak aynı CPU çekirdeğini kullanarak sırayla. Tüm bu GIL geçişi yürütmeye ek yük getirir. Bu, kodunuzun daha hızlı çalışmasını istiyorsanız, iş parçacığı paketini kullanmanın genellikle iyi bir fikir olmadığı anlamına gelir.

Python'un iş parçacığı paketini kullanmanın nedenleri var. Bazı şeyleri aynı anda çalıştırmak istiyorsanız ve verimlilik endişe verici değilse, o zaman tamamen iyi ve kullanışlıdır. Veya bir şey (bazı GÇ gibi) beklemesi gereken kod çalıştırıyorsanız, bu çok mantıklı olabilir. Ancak iş parçacığı kütüphanesi ekstra CPU çekirdeği kullanmanıza izin vermez.

Çoklu iş parçacığı, işletim sistemine (çoklu işlem yaparak), Python kodunuzu çağıran bazı harici uygulamalara (örneğin, Spark veya Hadoop) veya Python kodunuzun çağırdığı bazı kodlara (örn: Python'unuz olabilir) dış kaynak sağlanabilir. kod pahalı çok iş parçacıklı şeyler yapan bir C işlevi çağırır).


15

İki iş parçacığının aynı değişkene erişimi olduğunda bir sorununuz vardır. Örneğin C ++ 'da, sorunu önlemenin yolu, iki iş parçacığının aynı anda bir nesnenin ayarlayıcısını girmesini önlemek için bazı muteks kilit tanımlamaktır.

Python'da çoklu okuma mümkündür, ancak iki iplik aynı anda bir python komutundan daha küçük bir ayrıntı düzeyinde yürütülemez. Çalışan iş parçacığı GIL adında genel bir kilit alıyor.

Bu, çok çekirdekli işlemcinizden yararlanmak için çok iş parçacıklı kod yazmaya başlarsanız, performansınız artmayacaktır. Her zamanki geçici çözüm çoklu işlemden oluşur.

Örneğin C'de yazdığınız bir yöntemin içindeyseniz GIL'i serbest bırakmanın mümkün olduğunu unutmayın.

Bir GIL kullanımı Python'a özgü değildir, en yaygın CPython da dahil olmak üzere bazı yorumlayıcılarına özgüdür. (#edited, yoruma bakın)

GIL sorunu Python 3000'de hala geçerlidir.


Stackless hala bir GIL var. Yığınsız, diş açmayı geliştirmez (modülde olduğu gibi) - sorunu yan adım atmaya çalışan, ancak engellemeyen işlevler gerektiren farklı bir programlama yöntemi (coutinler) sunar.
jnoller

3.2'deki yeni GIL ne olacak?
yeni123456

Sadece bir iş parçacığı belleği güncelleyecek bir sorun / mutexes / semafor ihtiyacınız olmadığını eklemek için. @ new123456 çekişmeyi azaltır ve tek iş parçacıklı performansa (kendi başına etkileyici) zarar vermeden iş parçacıklarını daha iyi zamanlar, ancak yine de küresel bir kilittir.
Temel

14

Python 3.7 belgeleri

Ayrıca Python threadingbelgelerinden aşağıdaki alıntıyı vurgulamak istiyorum :

CPython uygulama ayrıntısı: CPython'da, Global Tercüman Kilidi nedeniyle, Python kodunu aynı anda yalnızca bir iş parçacığı yürütebilir (belirli performans odaklı kitaplıklar bu sınırlamanın üstesinden gelebilir). Uygulamanızın çok çekirdekli makinelerin hesaplama kaynaklarını daha iyi kullanmasını istiyorsanız multiprocessingveya seçeneğini kullanmanız önerilir concurrent.futures.ProcessPoolExecutor. Bununla birlikte, aynı anda birden fazla G / Ç bağlantılı görev çalıştırmak istiyorsanız, iş parçacığı oluşturma uygun bir modeldir.

Bu , GIL'in Python'daki dişli paralelliğin CPU'ya bağlı görevler için uygun olmadığını ima ettiği Sözlük girişineglobal interpreter lock bağlantı verir :

CPython yorumlayıcısı tarafından aynı anda yalnızca bir iş parçacığının Python bayt kodunu yürütmesini sağlamak için kullanılan mekanizma. Bu, nesne modelini (dict gibi kritik yerleşik türler dahil) eşzamanlı erişime karşı örtük olarak güvenli hale getirerek CPython uygulamasını basitleştirir. Tüm yorumlayıcının kilitlenmesi, çok işlemcili makinelerin sağladığı paralelliklerin çoğunu pahasına yorumlayıcının çok iş parçacıklı olmasını kolaylaştırır.

Bununla birlikte, standart veya üçüncü taraf olan bazı genişletme modülleri, sıkıştırma veya karma gibi hesaplama açısından yoğun görevler yaparken GIL'i serbest bırakacak şekilde tasarlanmıştır. Ayrıca, I / O yaparken GIL daima serbest bırakılır.

"Serbest iş parçacıklı" bir yorumlayıcı (paylaşılan verileri çok daha hassas bir şekilde kilitleyen) oluşturma çabaları başarılı olmamıştır çünkü ortak tek işlemcili durumda performanstan etkilenmiştir. Bu performans sorununun üstesinden gelmenin, uygulamayı daha karmaşık ve dolayısıyla sürdürülmesi daha pahalı hale getireceğine inanılmaktadır.

Bu alıntı ayrıca diktelerin ve dolayısıyla değişken atamanın da CPython uygulama detayı olarak iş parçacığı açısından güvenli olduğunu ima eder:

Daha sonra , multiprocessingpakete ilişkin dokümanlar, aşağıdakine benzer bir arayüz ortaya koyarken yumurtlama süreciyle GIL'in üstesinden nasıl geldiğini açıklar threading:

çoklu işlem, iş parçacığı modülüne benzer bir API kullanarak yumurtlama işlemlerini destekleyen bir pakettir. Çok işlemli paket, hem yerel hem de uzak eşzamanlılık sunar ve iş parçacıkları yerine alt işlemler kullanarak Global Tercüman Kilidini etkin bir şekilde yönlendirir. Bu nedenle, çok işlem modülü, programlayıcının belirli bir makinede birden fazla işlemciden tam olarak yararlanmasına izin verir. Hem Unix hem de Windows üzerinde çalışır.

Ve dokümanlarconcurrent.futures.ProcessPoolExecutor bunun multiprocessingbir arka uç olarak kullandığını açıklıyor :

ProcessPoolExecutor sınıfı, çağrıları eşzamansız olarak yürütmek için bir işlem havuzunu kullanan bir Executor alt sınıfıdır. ProcessPoolExecutor, Global Tercüman Kilidi'nin yan basamağını sağlayan çoklu işlem modülünü kullanır, aynı zamanda yalnızca seçilebilir nesnelerin yürütülebileceği ve iade edilebileceği anlamına gelir.

Diğer bir temel sınıf tezat gereken işlemlerin yerine parçacıkları kullanırThreadPoolExecutor

ThreadPoolExecutor, çağrıları eşzamansız olarak yürütmek için bir iş parçacığı havuzu kullanan bir Executor alt sınıfıdır.

ThreadPoolExecutorbundan yalnızca G / Ç bağlantılı görevler için uygun olduğu sonucuna varıyoruz.ProcessPoolExecutor , aynı zamanda CPU bağlantılı görevleri de gerçekleştirebilir.

Aşağıdaki soru, GIL'in neden ilk sırada var olduğunu soruyor: Neden Global Tercüman Kilidi?

Proses ve iplik deneyleri

At Threading Python vs Multiprocessing Python içinde parçacığı vs sürecinin deneysel analizi yaptıktan.

Sonuçların hızlı önizlemesi:

resim açıklamasını buraya girin


0

Python (CPython ve diğerleri) neden GIL kullanıyor?

Gönderen http://wiki.python.org/moin/GlobalInterpreterLock

CPython'da, global yorumlayıcı kilidi veya GIL, birden çok yerel iş parçacığının Python bayt kodlarını aynı anda yürütmesini engelleyen bir mutekstir. Bu kilit esas olarak CPython'un bellek yönetimi iş parçacığı için güvenli olmadığından gereklidir.

Python'dan nasıl kaldırılır?

Lua gibi, belki de Python birden fazla VM başlatabilir, ancak python bunu yapmaz, sanırım başka nedenler olmalı.

Numpy veya başka bir python genişletilmiş kütüphanesinde, bazen, GIL'in diğer iş parçacıklarına bırakılması tüm programın verimliliğini artırabilir.


0

Görsel Efektler için multithreading kitabından bir örnek paylaşmak istiyorum. İşte klasik ölü kilit durumu

static void MyCallback(const Context &context){
Auto<Lock> lock(GetMyMutexFromContext(context));
...
EvalMyPythonString(str); //A function that takes the GIL
...    
}

Şimdi sıradaki kilitlenmeye neden olan olayları düşünün.

╔═══╦════════════════════════════════════════╦══════════════════════════════════════╗
    Main Thread                             Other Thread                         
╠═══╬════════════════════════════════════════╬══════════════════════════════════════╣
 1  Python Command acquires GIL             Work started                         
 2  Computation requested                   MyCallback runs and acquires MyMutex 
 3                                          MyCallback now waits for GIL         
 4  MyCallback runs and waits for MyMutex   waiting for GIL                      
╚═══╩════════════════════════════════════════╩══════════════════════════════════════╝
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.