Python çoklu işlem Modülünün .join () Yöntemi Tam Olarak Ne Yapıyor?


110

Python Multiprocessing hakkında bilgi edinmek (bir PMOTW makalesinden ) ve join()yöntemin tam olarak ne yaptığına dair biraz açıklama yapmak isterim .

Bir In 2008 eski öğretici o olmadan belirtiyor p.join()aşağıdaki kodu çağrı, "çocuk süreç elle öldürmek gereken bir zombi haline sonlandırmak boşta ve olmayacaktır".

from multiprocessing import Process

def say_hello(name='world'):
    print "Hello, %s" % name

p = Process(target=say_hello)
p.start()
p.join()

Testin PIDyanı sıra time.sleeptest çıktısını da ekledim ve söyleyebileceğim kadarıyla süreç kendi kendine sona eriyor:

from multiprocessing import Process
import sys
import time

def say_hello(name='world'):
    print "Hello, %s" % name
    print 'Starting:', p.name, p.pid
    sys.stdout.flush()
    print 'Exiting :', p.name, p.pid
    sys.stdout.flush()
    time.sleep(20)

p = Process(target=say_hello)
p.start()
# no p.join()

20 saniye içinde:

936 ttys000    0:00.05 /Library/Frameworks/Python.framework/Versions/2.7/Reso
938 ttys000    0:00.00 /Library/Frameworks/Python.framework/Versions/2.7/Reso
947 ttys001    0:00.13 -bash

20 saniye sonra:

947 ttys001    0:00.13 -bash

Davranış, p.join()dosyanın sonuna geri eklendiğinde aynıdır . Haftanın Python Modülü , modülün çok okunabilir bir açıklamasını sunuyor ; "Bir işlemin çalışmasını tamamlayıp çıkmasını beklemek için, join () yöntemini kullanın.", Ancak en azından OS X bunu zaten yapıyor gibi görünüyor.

Yöntemin adını da merak ediyorum. Is .join()yöntem şey burada artarda? Sonu olan bir süreci birleştirmek mi? Yoksa Python'un yerel .join()yöntemiyle bir adı mı paylaşıyor ?


2
Bildiğim kadarıyla, ana iş parçacığını tutuyor ve alt işlemin tamamlamasını ve ardından ana iş parçacığındaki kaynakları geri birleştirmesini bekliyor, çoğunlukla temiz bir çıkış yapıyor.
abhishekgarg

ah bu mantıklı. Yani asıl CPU, Memory resourcessüreç ana süreçten ayrılıyor, sonra joinalt süreç tamamlandıktan sonra tekrar geri mi alınıyor?
MikeiLL

evet, yaptığı şey bu. Yani, onlara geri dönmezseniz, çocuk süreci bittiğinde, bu sadece geçersiz veya ölü bir süreç olarak yatar
abhishekgarg

@abhishekgarg Bu doğru değil. Ana süreç tamamlandığında alt süreçler dolaylı olarak birleştirilecektir.
dano

@dano, ben de python öğreniyorum ve testlerimde bulduklarımı paylaştım, testlerimde hiç bitmeyen bir ana süreç yaşadım, bu yüzden belki de bu çocuk süreçlerini neden geçersiz olarak gördüm.
abhishekgarg

Yanıtlar:


125

join()Yöntem kullanıldığında threadingveya multiprocessing, ilgili değildir str.join()- aslında Birlikte bir şey birleştirerek değil. Bunun yerine, "bu [iş parçacığı / işlem] 'in tamamlanmasını bekle" anlamına gelir. Ad join, multiprocessingmodülün API'sinin modülün API'sine benzer görünmesi gerektiği ve threadingmodülün nesnesi için threadingkullandığı joiniçin kullanılır Thread. Terimin join"bir iş parçacığının tamamlanmasını bekleyin" anlamında kullanılması birçok programlama dilinde yaygındır, bu nedenle Python da onu benimsemiştir.

Şimdi, hem çağrı ile hem de çağrı olmadan 20 saniyelik gecikmeyi görmenizin join()nedeni, varsayılan olarak, ana işlem çıkmaya hazır olduğunda join(), tüm çalışan multiprocessing.Processörnekleri örtük olarak çağıracak olmasıdır . Bu, multiprocessingdokümanlarda olması gerektiği kadar açıkça belirtilmemiştir , ancak Programlama Yönergeleri bölümünde bahsedilmektedir :

Daemonik olmayan süreçlerin otomatik olarak birleştirileceğini de unutmayın.

Sen ayarlayarak bu davranışı geçersiz kılabilirsiniz daemonüzerinde bayrak Processiçin Trueişleme başlamadan önce:

p = Process(target=say_hello)
p.daemon = True
p.start()
# Both parent and child will exit here, since the main process has completed.

Bunu yaparsanız , ana süreç tamamlanır tamamlanmaz alt süreç sonlandırılacaktır :

şeytan

İşlemin arka plan programı bayrağı, bir Boole değeri. Bu, start () çağrılmadan önce ayarlanmalıdır.

Başlangıç ​​değeri, yaratma sürecinden miras alınır.

Bir süreç çıktığı zaman, tüm arka plan programı alt süreçlerini sonlandırmaya çalışır.


6
Bunun p.daemon=True"ana programın çıkmasını engellemeden çalışan bir arka plan işlemini başlatmak" için olduğunu anlıyordum. Ancak "daemon süreci, ana program çıkmadan önce otomatik olarak sonlandırılırsa", tam olarak ne işe yarar?
MikeiLL

8
@MikeiLL Temelde, ana süreç çalıştığı sürece arka planda olmasını istediğiniz her şeydir, ancak bunun ana programdan çıkmadan önce zarif bir şekilde temizlenmesi gerekmez. Belki de bir soketten veya donanım aygıtından veri okuyan ve bu verileri bir kuyruk aracılığıyla üst öğeye geri besleyen veya bir amaç için arka planda işleyen bir çalışan işlem? Genel olarak bir daemonicçocuk süreci kullanmanın çok güvenli olmadığını söyleyebilirim , çünkü süreç, sahip olabileceği herhangi bir açık kaynağı temizlemeye izin vermeden sonlandırılacaktır .. (devam).
dano

7
@MikeiLL Ana işlemden çıkmadan önce çocuğa temizlemesi ve çıkması için işaret vermek daha iyi bir uygulama olacaktır. Ebeveyn çıktığında arka planda çalışan alt süreci çalışır halde bırakmanın mantıklı olacağını düşünebilirsiniz, ancak multiprocessingAPI'nin threadingAPI'yi olabildiğince yakından taklit edecek şekilde tasarlandığını unutmayın . Daemonic threading.Threadnesneler, ana iş parçacığı çıkar çıkmaz sonlandırılır, bu nedenle daemonik multiprocesing.Processnesneler aynı şekilde davranır.
dano

38

Olmadan join() ana süreç alt süreç tamamlanmadan tamamlanabilir. Bunun hangi koşullar altında zombiye yol açtığından emin değilim.

Temel amacı join(), ana süreç çocuk sürecin çalışmasına bağlı herhangi bir şey yapmadan önce bir çocuk sürecin tamamlanmasını sağlamaktır.

Bunun etimolojisi, Unix ailesi işletim sistemlerinde çocuk süreçler oluşturmak için kullanılan ortak terim olan join()tersi olmasıdır fork. Tek bir süreç bir çok süreç "çatallanır" ve ardından tekrar bir süreçte "birleşir".


2
Adı kullanır, join()çünkü join()bir threading.Threadnesnenin tamamlanmasını beklemek için kullanılır ve multiprocessingAPI, threadingAPI'yi olabildiğince taklit etmek içindir .
dano

İkinci ifadeniz, mevcut bir projede uğraştığım sorunu ele alıyor.
MikeiLL

Ana iş parçacığının alt işlemin tamamlanmasını beklediği kısmı anlıyorum, ancak bu, Eşzamansız yürütmenin amacını bozmaz mı? Yürütmeyi bağımsız bir şekilde (alt görev veya süreç) bitirmesi gerekmiyor mu?
Apurva Kunkulol

1
@ApurvaKunkulol Nasıl kullandığınıza bağlıdır, ancak join()ana iş parçacığının alt iş parçacığının çalışmasının sonuçlarına ihtiyaç duyması durumunda gereklidir. Örneğin, bir şey oluşturuyorsanız ve son görüntünün 1 / 4'ünü 4 alt işlemin her birine atıyorsanız ve tamamlandığında görüntünün tamamını görüntülemek istiyorsanız.
Russell Borogove

@RussellBorogove Ah! Anladım. O zaman Asenkron aktivitenin anlamı burada biraz farklıdır. Bu, yalnızca alt süreçlerin görevlerini ana iş parçacığı ile eşzamanlı olarak yerine getirmesi gerektiği ve ana iş parçacığının da alt süreçleri boşta beklemek yerine işini yaptığı anlamına gelmelidir.
Apurva Kunkulol

12

Ne olduğunu ayrıntılı olarak açıklamayacağım join, ama işte etimoloji ve arkasındaki önsezi, anlamını daha kolay hatırlamanıza yardımcı olacak.

Buradaki fikir, uygulamanın , birinin efendisi, geri kalanı işçiler (veya "köleler") olduğu çoklu süreçlere " çatallanması " dır. İşçiler bittiğinde, ana makineye "katılırlar", böylece seri yürütmeye devam edilebilir.

joinYöntem, bir işçinin kendisine katılmak üzere beklemek için ana işlemini neden olur. Yöntemin "bekle" olarak adlandırılması daha iyi olabilir, çünkü bu ana bilgisayarda neden olduğu gerçek davranış (ve POSIX'te buna "katılma" da dese de bu, POSIX'te denir). Birleştirme yalnızca doğru şekilde işbirliği yapan dişlerin bir etkisi olarak gerçekleşir, bu ustanın yaptığı bir şey değildir .

"Çatal" ve "birleştirme" adları 1963'ten beri çoklu işlemede bu anlamla kullanılmaktadır .


Yani bir şekilde kelimenin bu kullanımı join, diğer yolun aksine, birleştirme ile ilgili olarak kullanılmasından önce gelmiş olabilir.
MikeiLL

1
Birleştirmede kullanımın çoklu işlemede kullanımdan kaynaklanması olası değildir; daha ziyade her iki duyu da kelimenin sade-İngilizce anlamından ayrı olarak türemiştir.
Russell Borogove

2

join()çalışan işlemlerin çıkmasını beklemek için kullanılır. Bir çağırmalıdır close()veya terminate()kullanmadan önce join().

@Russell belirtildiği gibi birleştirme tam tersi olan çatal (ki spawns alt işlemler).

Çalışmaya katılmak için çalıştırmanız gerekir; close()bu, daha fazla görevin havuza gönderilmesini önleyecek ve tüm görevler tamamlandığında çıkacaktır. Alternatif olarak, çalıştırma terminate()tüm çalışan işlemleri hemen durdurarak çıkacaktır.

"the child process will sit idle and not terminate, becoming a zombie you must manually kill" bu, ana (üst) süreç çıktığı, ancak alt süreç hala çalıştığı ve tamamlandıktan sonra çıkış durumunu döndürecek bir üst süreç olmadığı zaman mümkündür.


2

join()Tüm çoklu işlem süreçleri tamamlandıktan önce kodun daha sonraki satırlar olarak adlandırılan olmadığını çağrı olmasını sağlar.

Örneğin, olmadan, join()aşağıdaki kod restart_program()süreçler bitmeden bile çağırır , bu eşzamansız'a benzer ve istediğimiz şey değildir (deneyebilirsiniz):

num_processes = 5

for i in range(num_processes):
    p = multiprocessing.Process(target=calculate_stuff, args=(i,))
    p.start()
    processes.append(p)
for p in processes:
    p.join() # call to ensure subsequent line (e.g. restart_program) 
             # is not called until all processes finish

restart_program()

0

Bir işlemin çalışmasını tamamlayıp çıkmasını beklemek için join () yöntemini kullanın.

ve

Not Arka plan makineye, sonlandırmayı yansıtacak şekilde nesnenin durumunu güncellemesi için süre vermek amacıyla, işlemi sonlandırdıktan sonra sürece katılmak () önemlidir.

Bu, anlamama yardımcı olan iyi bir örnek: burada

Şahsen fark ettiğim bir şey, ana sürecimin, çocuk multiprocessing.Process(), ilk başta kullandığım noktayı yenen join () yöntemini kullanarak sürecini bitirene kadar duraklatılmasıydı .

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.