Bir önceki yazımda Thread ve Process kavramlarını açıklamıştım. Çoklu Thread ve Process ihtiyacından bahsedip Thread üzerine kısa bir örnek yapmıştım, şimdi de Process sayısını nasıl arttırabiliriz bunun üzerine bir şeyler söyleyeyim.
Yeni Process’ler oluşturmak için yine Thread benzeri bir Python modülümüz var. multiprocessing isimli bu modül içinde Process sınıfı ile işlemlerimizi yapacağız.
Pool Sınıfı: Havuz anlamındaki bu sınıf bize bir Process havuzu oluşturmamızı ve verdiğimiz işlemleri bu havuz içindeki process‘ler ile yapmamızı sağlar. Yönetimi onu oluşturan process’e aittir. Pool sınıfına ait metotların gösterildiği dokümantasyondaki küçük örneğe bakalım;
from multiprocessing import Pool import time def f(x): return x*x if __name__ == '__main__': with Pool(processes=4) as pool: # 4 işçi process'li Pool result = pool.apply_async(f, (10,)) # 1 print(result.get(timeout=1)) # 2 print(pool.map(f, range(10))) # 3 it = pool.imap(f, range(10)) # 4 print(next(it)) # "0" basar print(next(it)) # "1" basar print(it.next(timeout=1)) # "4" basar result = pool.apply_async(time.sleep, (10,)) print(result.get(timeout=1))
İşaretlediğim yerleri açıklamaya çalışayım.
1: bir process’te asenkron olarak fonksiyonumuzu çalıştırıyoruz
2: bir önceki işlemin sonucu getiriyoruz. Burada çok yavaş bir işlemciniz var ise sonuç henüz hazır olmayacağı için dönüş olmayabilir.
3: senkron bir biçimde 1den 10a kadar olan sayıların karesi konsola basılacaktır
4: “3”teki işlemin Generator bir fonksiyon dönen daha tembel hali ama büyük işlemlerde performanslı hali.
Metotlardaki timeout parametresi verilen sürede işlemin yapılmasını söyler yoksa “multiprocessing.TimeoutError” hatası verecektir.
Process sınıfını tek başına kullanımı ise Thread sınıfına benzer şekildedir. Yine dokümantasyon içindeki örneği açıklayayım.
from multiprocessing import Process import os def info(title): print(title) print('module name:', __name__) print('parent process:', os.getppid()) print('process id:', os.getpid()) def f(name): info('function f') print('hello', name) if __name__ == '__main__': info('main line') p = Process(target=f, args=('bob',)) p.start() p.join() # çıktı şuna benzer olmalı # main line # module name: __main__ # parent process: 8744 # process id: 5276 # function f # module name: __mp_main__ # parent process: 5276 # process id: 5756 # hello bob
Yine bir target parametresine fonksiyon adımızı vererek process’imizi başlattık. Oluşturduğumuz info fonksiyonu ve os modülü ile info fonksiyonunun çağrıldığı process hakkında bilgileri konsola bastık. Burada ilk process’in id’si ikinci process’in “parent id”si olmasına dikkat edelim.
Process’ler Arası İletişim
İki yol ile mümkün. Pipe ve Queue sınıfları. Queue için şu örneğe bakalım;
from multiprocessing import Process, Queue def f(q): q.put([42, None, 'hello']) if __name__ == '__main__': q = Queue() p = Process(target=f, args=(q,)) p.start() print(q.get()) # "[42, None, 'hello']" p.join()
Kod açık yeterince. Bir Queue nesnesi oluşturulup child process içinde atanan değere parent process içinde erişilebiliyor.
Pipe ise bize iki nesne döndürüyor ve bunları child ve parent process’lerde kullanmamızı istiyor.
from multiprocessing import Process, Pipe def f(conn): conn.send([42, None, 'hello']) conn.close() if __name__ == '__main__': parent_conn, child_conn = Pipe() p = Process(target=f, args=(child_conn,)) p.start() print(parent_conn.recv()) # "[42, None, 'hello']" p.join()
Daha çok çeviri gibi bir yazı oldu, standartlar belli az çok zaten yorum katılacak tek yer kod örnekleri olabilirdi herhalde. Kaynağı da buraya yazarak bitiriyorum https://docs.python.org/3.6/library/multiprocessing.html
Bir cevap yazın