Python multiprocessing Sorunu

Merhaba İhsan Bey. multiprocessing kullanan herkesin bilmesi gereken bir kaç önemli şey var.
Öncelikle __name__ değişkeninin sadece ana programda, yani ilk process de "__main__"
değerine sahip olduğunu gözden kaçırıyorsunuz. Şu kodu deneyelim:

from multiprocessing import Process

def yaz():
    print(__name__)

if __name__ == '__main__':
    p = Process(target=yaz)
    p.start()
    input() # terminal kapanmasın diye

Bu kodu çalıştırdığınızda terminale __mp_main__ yazıldığınızı görebilirsiniz, ki bu sizin hata mesajınızda da yer alıyor:

AttributeError: Can't get attribute 'yaz' on <module '__mp_main__' from 'C:\\Users\\ihsan\\PycharmProjects\\NorkQTaskKiller\\abramanagerUI.py'>

Şimdi şuna dikkat edelim ki if __name__=="__main__:" diye bir bölüme sahibiz. Eğer bu bölümün içinde bir değişken tanımlarsak oluşturacağımız yeni processler bunlara erişemez. Aynı sizin yaz fonksiyonunuzda olduğu gibi (sonuçta o da bir değişken):

Çünkü yeni bir process başlatıldığında aslında sizin yazdığınız kodun aynısı işlemcinin farklı bir çekirdeğinde baştan başlatılır. Tabii __name__ değişkeni değiştirilerek. İşte bu yüzden bu kodu yazdığınızda:

if __name__ == "__main__":

    def yaz():
        ui.yaz()

    get_real_time = Process(target=yaz) 
    get_real_time.start()

Yeni başlattığınız process if __name__ == "__main__": kısmının içerisine girmez (bu yüzden bu bölümü multiprocessing kullanırken hep yazıyoruz. Yoksa bu da yeni bir process başlatırdı ve hep yeni processler başlatılmaya devam ederdi.), çünkü __name__ değişkeni artık "__main__" değildir (mesela sizin programınızda '__mp_main__' dı. Yukarıda bunu ekrena yazdırarak da görmüştük.) Bu if ifadesinin içine girilmediğinde de yaz fonksiyonu yeni procesimiz için tanımlanmamış oluyor. O yüzden bu değişkeni if __name__ == "__main__": nin dışında tanımlamanız gerekmekte. Aynı bu çalışan örnekte olduğu gibi:

from multiprocessing import Process


def yaz():
    print("ihsan")

if __name__ == '__main__':
    p = Process(target=yaz)
    p.start()

Şimdi

Kısmına gelirsek, target parametresine verdiğiniz değişkenler eğer bir python değişkeni ise multiprocessing modülü, pickle modülünü kullanarak bu değişkeni yeni process’e aktarmaya çalışır. Ancak QWidget nesneleri aslında tamamen bir python nesnesi değildir. Sonuç olarak QT kütüphanesi aslen python da yazılmamıştır, PyQt kütüphanesi de sadece binding sağlamaktadır. Yani bu nesneler saf python nesneleri olmadığı için pickle modülü bunlar üzerinde çalışamıyor, bu da size yukarıdaki hatayı veriyor. Bir örnek vermek gerekirse bu kodu çalıştırdığımızda:

from PyQt5 import QtWidgets
import pickle
import sys

app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
pickle.dumps(w)

Şu hatayı alıyoruz (ki bu sizin aldığınız hata ile aynı):

Traceback (most recent call last):
  File "C:\Users\Dinçel\Desktop\istihza denemeleri.py", line 8, in <module>
    pickle.dumps(w)
TypeError: can't pickle QWidget objects

Şimdi sonuç kısmına gelirsek, multiprocessing kullanmazın yanlış. Neden multiprocessing
modülünü kullanmak istediğinizi iyi düşünmelisiniz, ki zaten PyQt arayüz nesnelerini multiprocessing ile kullanamazsınız. Çünkü yukarıda da anlattığımız gibi process ler arasında aktarılamıyorlar. threading modülü işinizi görecekse onu kullanmalısınız. Ayrıca ben neden multiprocessing i arayüz nesnelerini parametre vererek çağırdığınızı anlayabilmiş değilim. Amacınızı threading ile de ulaşabileceğinizi düşünüyorum. Kütüphane seçiminiz hakkında buraya bakmanızı tavsiye ederim.

1 Beğeni