#python #multithreading #ciekawostka
Ostatnio refaktorowałem jeden ze swoich projektów, gdzie kluczowa część jest oparta na wielowątkowości. Tej "wirtualnej" limitowanej przez GIL'a :)
Jak wiadomo, threading.Thread
to tak na prawdę dzielenie głównego procesu na mniejsze subprocesy, które współdzielą pamięć (Mogą też zaalokować swoją przy użyciu Thread.local
, ale nadal w obrębie wyższej warstwy). Każdy z tych subprocesów działa we własnym zakresie, ale nadal w obrębie głównego procesu, czyli nie ma tutaj mowy o prawdziwym paraellismie pod taski typu cpu-based. Pod I/O jak najbardziej i taki też był mój case. Jest to tzw time-slicing
czyli nic innego jako dzielenie czasu procesora i skakanie z jednego "wątku" na drugi.
Mam use cases, gdzie zagnieżdżam jeden "wątek" w drugim. Z początku byłem przekonany, że takie rozwiązanie "przedzieli" istniejący już subprocess na kolejny subprocess, czyli ponownie - Zagnieżdżony wątek będzie zależny od rodzica w którym został zagnieżdżony. Obrazując:
Jak się jednak okazuję, hierarchia "wirtualnych" wątków jest płaska. Oznacza to w praktyce, że bez względu na zagnieżdżanie, czy też nie, każdy nowy "wątek" zawsze będzie tworzony na jednakowym poziomie, czyli nie występuje relacje parent-child pomiędzy zagnieżdżonymi wątkami (Nie wliczając głównego procesu). Finalnie będzie to wyglądać tak:
Prosty test:
import threading
import time
def child():
time.sleep(10)
print("finished child processing")
def parent():
ch = threading.Thread(target=child)
ch.start()
print("finished parent processing")
def main():
p = threading.Thread(target=parent)
p.start()
p.join()
print("finished main")
if __name__ == "__main__":
main()
--> finished parent processing
--> finished main
--> finished child processing
Gdy by zaszła relacja parent--child, to w momencie skończenia procesu parent, child powinien zostać zterminowany a tak nie jest. Oczywiście mógłbym dodać join()
na poziomie parent, żeby poczekać na pełną egzekucje child. Anyway powyższe wskazuję, że child w żaden sposób nie jest zależny od parent.
Czy gdziekolwiek to działa inaczej? W mojej głowie wątki to od zawsze niezależne byty tj. nie ma zależności parent <-> kid. Przypadek dla
parent<->kid
jest bardzo popularny np.fork-join model
, ale to nie oznacza, że reszta nie ma sensu