2012-05-16 25 views
16

Python yorumlayıcısını çok iş parçacıklı bir C uygulamasına yerleştiriyorum ve iş parçacığı güvenliğini sağlamak için hangi API'ları kullanmam gerektiği konusunda kafam karıştı. piton gömerken Anlamıştım kadarıylaPython'u çok iş parçacıklı C uygulamasında gömme

, başka herhangi bir Python C API çağrısını çağırmadan önce GiL kilit bakmak yerleştirerrtarafmdan kalmıştır. Bu durum, bu işlevlerle yapılabilir:

gstate = PyGILState_Ensure(); 
// do some python api calls, run python scripts 
PyGILState_Release(gstate); 

Ama bu tek başına yeterli görünmüyor. Python API'ları için karşılıklı dışlama sağlamayacak gibi göründüğü için hala rastgele çökmelerim var. Sağ Py_IsInitialized() çağrısının

PyEval_InitThreads(); 

ama kafa karıştırıcı kısmı devreye giriyor:

Ben de eklendi biraz daha docs okuduktan sonra.

başlat ve küresel tercüman

Bu, bu işlevin döndürdüğü GIL farz edildiğinde kilitlenmesini ve bir şekilde kilidi gerektiğini önermektedir kilidi kazanmak: docs bu işlev belirtmektedirler. ama pratikte bu gerekli görünmüyor. Bu satır ile benim multithreaded çalıştım mükemmel ve karşılıklı dışlama PyGILState_Ensure/Release işlevleri tarafından korunur.
PyEval_ReleaseLock()'u PyEval_ReleaseLock() ekledikten sonra uygulama PyImport_ExecCodeModule() sonraki aramaya hızlı bir şekilde kilitlendi.

Burada neyi özlüyorum?

cevap

4

Sonunda bunu çözdüm.

PyEval_InitThreads(); 

sonra düzgün ana iş parçacığı için GIL serbest iken

PyEval_SaveThread(); 

çağırmanız gerekir.

+0

Bu yanlış ve potansiyel olarak zararlı: 'PyEval_SaveThread' her zaman PyEval_RestoreThread ile bağlantılı olmalıdır. [Başka yerlerde açıklandığı gibi] (http://stackoverflow.com/a/15471525/1600898), kilidi başlattıktan sonra serbest bırakmaya çalışmamalısınız; Onu düzenli çalışmasının bir parçası olarak bırakmak için Python'a bırakın. – user4815162342

+0

Tüm çağrıları bir _Block_ _Allow_ bloğunda python'a koyarsanız neden zararlı olduğunu anlamıyorum. Öte yandan, eğer PyEval_SaveThread(); 'i çağırmazsanız, ana parçanız diğer iş parçacıklarının Python'a erişimini engelleyecektir. Başka bir deyişle PyGILState_Ensure() 'deadlocks. – khkarens

+0

Her ikisi de Python'u gömmek ve bir uzantı modülüne çağırmak için çalışan tek şey. –

-1

tek CPython örneğinin birden Python dişlerine birden çok iş parçacığı iletişim kurmaya çalışan bir çok kanallı C uygulaması olan şirket bana riskli görünüyor.

Sürece sadece bir adet C parçacığı Python ile Python uygulaması çoklu iş parçacığı olsa bile kilitleme konusunda endişelenmenize gerek olmamalıdır iletişim kurar. Birden çok python iş parçacığına ihtiyacınız varsa, uygulamayı bu şekilde ayarlayabilirsiniz ve birden çok C iş parçacığı, birden çok Python iş parçacığı için bunları çiftleştiren tek C iş parçacığı ile bir sıra aracılığıyla iletişim kurabilir. İşinize yarayacak

alternatif (C programı aracılığıyla olmalıdır Python programları arasındaki ders iletişimin) ihtiyacı her C parçacığı için birden CPython örneklerini birine sahip olmaktır.

Başka bir alternatif Stackless Python yorumlayıcısı olabilir. Bu GIL ile ortadan kalkıyor, ancak birden çok ileti dizisine bağlanan diğer sorunlara gittiğinizden emin değilim. stackless (benim tek iş parçacıklı) C uygulama için bir drop-in yerine oldu.

+1

Soruyu gerçekten cevaplamamak için elinizden geleni yaptınız. İşi tek bir iş parçacığına kuyruğa almakla ilgilenmiyorum. – shoosh

5

Tam olarak aynı sorunla karşılaştım ve şimdi PyEval_SaveThread()'u, PyEval_InitThreads()'dan hemen sonra önerdiğin gibi çözdüm.Ancak, benim asıl sorunum, PyInitialise()'dan sonra PyEval_InitThreads() kullandım ve sonra farklı, daha sonra gelen yerel dizilerden arandığında PyGILState_Ensure()'un engellenmesiydi. genel değişken vardır

  1. : bir ana dizisinden

    static int gil_init = 0; 
    
  2. doğal C uzantısını yüklemek ve Python yorumlayıcısı başlatın:

    Py_Initialize() 
    
  3. Özetle, bu Şimdi ne yaptığım olduğunu
  4. Diğer birden çok iş parçacığımdan uyguladığım, aynı anda Python/C API'sine çok sayıda çağrı yapıyor:

    Ana dizisinden
    if (!gil_init) { 
        gil_init = 1; 
        PyEval_InitThreads(); 
        PyEval_SaveThread(); 
    } 
    state = PyGILState_Ensure(); 
    // Call Python/C API functions...  
    PyGILState_Release(state); 
    
  5. Python yorumlayıcısı

    Py_Finalize() 
    

Ya denedim diğer tüm çözümler durdurmak PyGILState_Ensure() kullanarak engelleme rastgele Python sigfaults veya kilitlenme/neden oldu.

Python belgeleri gerçekten bu konuda daha açık olmalı ve en azından hem yerleştirme hem de uzantı kullanım durumları için bir örnek sunmalıdır.

İlgili konular