Python Threading: Bevezetés – etoppc.com

Ebből az oktatóanyagból megtudhatja, hogyan használhatja a Python beépített szálfűző modulját a Python többszálas képességeinek felfedezéséhez.

A folyamatok és szálak alapjaitól kezdve megtanulhatja, hogyan működik a többszálú feldolgozás Pythonban – miközben megérti a párhuzamosság és a párhuzamosság fogalmát. Ezután megtanulhatja, hogyan indítson el és futtasson egy vagy több szálat a Pythonban a beépített szálfűző modul segítségével.

Kezdjük el.

Folyamatok vs. szálak: mi a különbség?

Mi az a folyamat?

A folyamat egy program bármely példánya, amelynek futnia kell.

Bármi lehet – Python-szkript vagy webböngésző, például Chrome egy videokonferencia-alkalmazáshoz. Ha elindítja a Feladatkezelőt a gépen, és a Teljesítmény -> CPU elemre navigál, akkor láthatja a CPU magokon jelenleg futó folyamatokat és szálakat.

A folyamatok és szálak megértése

Belsőleg egy folyamatnak van egy dedikált memóriája, amely a folyamatnak megfelelő kódot és adatokat tárolja.

Egy folyamat egy vagy több szálból áll. A szál az utasítások legkisebb sorozata, amelyet az operációs rendszer végrehajthat, és a végrehajtás folyamatát reprezentálja.

Minden szálnak megvan a maga verem és regiszter, de nincs dedikált memória. A folyamathoz kapcsolódó összes szál hozzáférhet az adatokhoz. Ezért az adatokat és a memóriát a folyamat összes szála megosztja.

Egy N maggal rendelkező CPU-ban N folyamat tud párhuzamosan végrehajtani ugyanabban az időben. Ugyanazon folyamat két szála azonban soha nem futhat párhuzamosan, de párhuzamosan. Az egyidejűség és a párhuzamosság fogalmával a következő részben foglalkozunk.

Az eddig tanultak alapján foglaljuk össze a folyamat és a szál közötti különbségeket.

FeatureProcessThreadMemory Dedikált memóriaMegosztott memória VégrehajtásmódPárhuzamos, párhuzamos Egyidejű; de nem párhuzamos végrehajtás, amelyet az Operating SystemCPython Interpreter kezel

Többszálú feldolgozás Pythonban

A Pythonban a Global Interpreter Lock (GIL) biztosítja, hogy csak egy szál tudja megszerezni a zárolást és futni bármikor. Minden szálnak meg kell szereznie ezt a zárolást a futáshoz. Ez biztosítja, hogy egy adott időpontban csak egyetlen szál legyen végrehajtásban, és elkerülhető az egyidejű többszálú feldolgozás.

  A PSP Vita Hard Reset végrehajtása

Vegyünk például ugyanannak a folyamatnak két szálát, a t1-et és a t2-t. Mivel a szálak ugyanazokat az adatokat osztják meg, amikor t1 egy adott k értéket olvas, t2 módosíthatja ugyanazt a k értéket. Ez holtpontokhoz és nemkívánatos eredményekhez vezethet. De csak az egyik szál szerezheti meg a zárolást és futhat bármely példányban. Ezért a GIL gondoskodik a menetbiztonságról is.

Tehát hogyan érhetjük el a többszálú képességeket a Pythonban? Ennek megértéséhez beszéljük meg a párhuzamosság és a párhuzamosság fogalmát.

Egyidejűség vs. párhuzamosság: áttekintés

Vegyünk egynél több magos CPU-t. Az alábbi ábrán a CPU négy magból áll. Ez azt jelenti, hogy egy adott pillanatban négy különböző művelet futhat párhuzamosan.

Ha négy folyamat van, akkor mindegyik folyamat önállóan és egyidejűleg futhat mind a négy magon. Tegyük fel, hogy minden folyamatnak két szála van.

A szálkezelés működésének megértéséhez váltsunk többmagos processzor architektúráról egymagos architektúrára. Mint említettük, csak egyetlen szál lehet aktív egy adott végrehajtási példányon; de a processzormag tud váltani a szálak között.

Például az I/O-hoz kötött szálak gyakran várnak az I/O műveletekre: olvasás a felhasználói bevitelben, adatbázis-olvasás és fájlműveletek. Ez alatt a várakozási idő alatt feloldhatja a zárat, hogy a másik szál futhasson. A várakozási idő egyszerű művelet is lehet, például n másodperces alvás.

Összefoglalva: A várakozási műveletek során a szál feloldja a zárolást, lehetővé téve a processzormag számára, hogy másik szálra váltson. A korábbi szál végrehajtása a várakozási időszak letelte után folytatódik. Ez a folyamat, ahol a processzormag egyidejűleg vált a szálak között, megkönnyíti a többszálú feldolgozást. ✅

Ha folyamatszintű párhuzamosságot kíván megvalósítani az alkalmazásában, fontolja meg inkább a többfeldolgozás használatát.

Python Threading modul: Első lépések

A Python egy szálfűző modult tartalmaz, amelyet importálhat a Python-szkriptbe.

import threading

Szálobjektum létrehozásához Pythonban használhatja a Thread konstruktort: ​​threading.Thread(…). Ez az általános szintaxis, amely elegendő a legtöbb szálfűzési megvalósításhoz:

threading.Thread(target=...,args=...)

Itt,

  • A target a kulcsszó argumentuma, amely egy Python hívható elemet jelöl
  • Az args az argumentumok sorozata, amelyet a célpont befogad.

Az oktatóanyagban szereplő kódpéldák futtatásához Python 3.x-re lesz szüksége. Töltse le a kódot, és kövesse a lépést.

  A sudo hozzáférés vezérlése Linuxon

Szálak meghatározása és futtatása Pythonban

Definiáljunk egy szálat, amely egy célfüggvényt futtat.

A célfüggvény a some_func.

import threading
import time

def some_func():
    print("Running some_func...")
    time.sleep(2)
    print("Finished running some_func.")

thread1 = threading.Thread(target=some_func)
thread1.start()
print(threading.active_count())

Elemezzük, mit csinál a fenti kódrészlet:

  • Importálja a szálfűzést és az időmodulokat.
  • A some_func függvénynek leíró print() utasításai vannak, és két másodperces elalvási műveletet tartalmaz: a time.sleep(n) hatására a függvény n másodpercig alvó állapotba kerül.
  • Ezután definiálunk egy szálszálat, amelynek a cél a some_func. threading.Thread(target=…) létrehoz egy szál objektumot.
  • Megjegyzés: A függvény nevét adja meg, ne függvényhívást; használd a some_func-ot és ne a some_func().
  • Szálobjektum létrehozása nem indít el szálat; a start() metódus meghívása a szál objektumon megteszi.
  • Az aktív szálak számának meghatározásához az active_count() függvényt használjuk.

A Python szkript fut a fő szálon, és létrehozunk egy másik szálat (thread1) a some_func függvény futtatásához, így az aktív szálak száma kettő, amint az a kimeneten látható:

# Output
Running some_func...
2
Finished running some_func.

Ha közelebbről megnézzük a kimenetet, azt látjuk, hogy a thread1 indításakor lefut az első print utasítás. Az alvó üzemmódban azonban a processzor a fő szálra vált, és kinyomtatja az aktív szálak számát – anélkül, hogy megvárná, amíg a szál1 végrehajtása befejeződik.

Várakozás a szálak végrehajtásának befejezésére

Ha azt szeretné, hogy a thread1 befejezze a végrehajtást, a szál elindítása után hívhatja meg rajta a join() metódust. Ezzel megvárja, amíg az 1. szál befejezi a végrehajtást anélkül, hogy a fő szálra váltana.

import threading
import time

def some_func():
    print("Running some_func...")
    time.sleep(2)
    print("Finished running some_func.")

thread1 = threading.Thread(target=some_func)
thread1.start()
thread1.join()
print(threading.active_count())

Most a thread1 végrehajtása befejeződött, mielőtt kinyomtatjuk az aktív szálak számát. Tehát csak a főszál fut, ami azt jelenti, hogy az aktív szálak száma egy. ✅

# Output
Running some_func...
Finished running some_func.
1

Több szál futtatása Pythonban

Ezután hozzunk létre két szálat két különböző funkció futtatásához.

Itt a count_down egy olyan függvény, amely egy számot vesz fel argumentumként, és ettől a számtól számol vissza nulláig.

def count_down(n):
    for i in range(n,-1,-1):
        print(i)

Meghatározzuk a count_up, egy másik Python-függvényt, amely nullától egy adott számig számol.

def count_up(n):
    for i in range(n+1):
        print(i)

📑 Ha a range() függvényt a szintaxistartománnyal (start, stop, step) használja, akkor a végpont stop alapértelmezés szerint ki van zárva.

  Rendezd az összes Reddit-bejegyzést hivatkozásokba, képekbe és videókba

– Ha egy adott számról nullára szeretne visszaszámolni, használhat -1 negatív lépésértéket, és állítsa a stop értéket -1-re, hogy a nulla szerepeljen.

– Hasonlóképpen, ha n-ig akar számolni, a stop értéket n + 1-re kell állítani. Mivel a start és step alapértelmezett értéke 0, illetve 1, a tartomány(n + 1) segítségével megkaphatja a 0 sorozatot. n-en keresztül.

Ezután definiálunk két szálat, a szál1-et és a szál2-t a count_down és a count_up függvények futtatásához. Mindkét funkcióhoz nyomtatási utasításokat és alvási műveleteket adunk.

A szálobjektumok létrehozásakor vegye figyelembe, hogy a célfüggvény argumentumait sorként kell megadni – az args paraméterhez. Mivel mindkét függvény (count_down és count_up) egy argumentumot vesz fel. Az érték után kifejezetten vesszőt kell beszúrnia. Ez biztosítja, hogy az argumentum továbbra is sorként kerüljön átadásra, mivel a következő elemeket a rendszer None-ként értelmezi.

import threading
import time

def count_down(n):
    for i in range(n,-1,-1):
        print("Running thread1....")
        print(i)
        time.sleep(1)


def count_up(n):
    for i in range(n+1):
        print("Running thread2...")
        print(i)
        time.sleep(1)

thread1 = threading.Thread(target=count_down,args=(10,))
thread2 = threading.Thread(target=count_up,args=(5,))
thread1.start()
thread2.start()

A kimenetben:

  • A count_up függvény a 2. szálon fut, és 5-ig számol 0-tól kezdve.
  • A count_down függvény az 1. szálon fut, 10-ről 0-ra visszaszámlál.
# Output
Running thread1....
10
Running thread2...
0
Running thread1....
9
Running thread2...
1
Running thread1....
8
Running thread2...
2
Running thread1....
7
Running thread2...
3
Running thread1....
6
Running thread2...
4
Running thread1....
5
Running thread2...
5
Running thread1....
4
Running thread1....
3
Running thread1....
2
Running thread1....
1
Running thread1....
0

Látható, hogy a szál1 és a szál2 felváltva fut, mivel mindkettő várakozási műveletet (alvó üzemmódot) foglal magában. Miután a count_up függvény befejezte az 5-ig való számlálást, a szál2 már nem aktív. Így csak a szál1-nek megfelelő kimenetet kapjuk.

Összegezve

Ebben az oktatóanyagban megtanulta, hogyan használhatja a Python beépített szálfűző modulját a többszálú feldolgozás megvalósítására. Íme egy összefoglaló a legfontosabb tudnivalókról:

  • A Thread konstruktorral szál objektum hozható létre. A threading.Thread(target=,args=())) létrehoz egy szálat, amely a hívható célt az args-ben megadott argumentumokkal futtatja.
  • A Python program egy főszálon fut, így a létrehozott szálobjektumok további szálak. Meghívhatja az active_count() függvényt, amely visszaadja az aktív szálak számát bármely példányban.
  • Elindíthat egy szálat a start() metódussal a szál objektumon, és megvárhatja, amíg a végrehajtás befejeződik a join() metódussal.

További példákat kódolhat a várakozási idők módosításával, más I/O műveletek kipróbálásával stb. Ügyeljen arra, hogy a közelgő Python-projektjeiben többszálat alkalmazzon. Boldog kódolást!🎉