logo

Multithreading en Python

Aquest article tracta els conceptes bàsics del multithreading en el llenguatge de programació Python. Igual que multiprocessament , el multithreading és una manera d'aconseguir la multitasca. En multithreading, el concepte de fils s'utilitza. Entenem primer el concepte de fil en arquitectura informàtica.

Què és un procés en Python?

En informàtica, a procés és una instància d'un programa informàtic que s'està executant. Qualsevol procés té 3 components bàsics:



  • Un programa executable.
  • Les dades associades que necessita el programa (variables, espai de treball, buffers, etc.)
  • El context d'execució del programa (estat del procés)

Una introducció a Python Threading

A fil és una entitat dins d'un procés que es pot programar per a l'execució. A més, és la unitat de processament més petita que es pot realitzar en un sistema operatiu (sistema operatiu). En paraules senzilles, un fil és una seqüència d'aquestes instruccions dins d'un programa que es pot executar independentment d'un altre codi. Per simplificar, podeu suposar que un fil és simplement un subconjunt d'un procés! Un fil conté tota aquesta informació en a Bloc de control de fil (TCB) :

  • Identificador del fil: S'assigna un identificador únic (TID) a cada fil nou
  • Apuntador de pila: Assenyala la pila del fil en el procés. La pila conté les variables locals sota l'abast del fil.
  • Comptador de programes: un registre que emmagatzema l'adreça de la instrucció que està executant un fil.
  • Estat del fil: pot estar en execució, llest, esperant, començant o acabat.
  • Conjunt de registres del fil: registres assignats al fil per a càlculs.
  • Punter del procés pare: Un punter al bloc de control de processos (PCB) del procés on viu el fil.

Considereu el diagrama següent per entendre la relació entre el procés i el seu fil:

multithreading-python-11

Relació entre un procés i el seu fil



Poden existir diversos fils dins d'un procés on:

  • Cada fil conté el seu conjunt de registres i variables locals (emmagatzemades a la pila) .
  • Tots els fils d'un procés comparteixen variables globals (emmagatzemades en un munt) i la codi del programa .

Considereu el diagrama següent per entendre com existeixen diversos fils a la memòria:

cerca binària
multithreading-python-21

Existència de múltiples fils a la memòria



Una introducció al Threading a Python

Multithreading es defineix com la capacitat d'un processador per executar diversos fils simultàniament. En una CPU senzilla d'un sol nucli, s'aconsegueix utilitzant canvis freqüents entre fils. Això s'anomena canvi de context . En el canvi de context, l'estat d'un fil es desa i l'estat d'un altre fil es carrega cada vegada que es produeix alguna interrupció (deguda a E/S o configurada manualment). El canvi de context es produeix amb tanta freqüència que tots els fils semblen córrer paral·lelament (això s'anomena multitasca ).

Considereu el diagrama següent en què un procés conté dos fils actius:

multithreading-python-31

Multithreading

Multithreading en Python

En Python , el roscat El mòdul proporciona una API molt senzilla i intuïtiva per generar diversos fils en un programa. Intentem entendre el codi multithreading pas a pas.

Pas 1: Mòdul d'importació

Primer, importeu el mòdul de fil.

import threading>

Pas 2: Crea un fil

Per crear un fil nou, creem un objecte del Fil classe. Pren els 'target' i 'args' com a paràmetres. El objectiu és la funció que ha d'executar el fil mentre que el args és els arguments que s'han de passar a la funció de destinació.

t1 = threading.Thread(target, args) t2 = threading.Thread(target, args)>

Pas 3: Iniciar un fil

Per iniciar un fil, fem servir el començar() mètode de la classe Thread.

t1.start() t2.start()>

Pas 4: Finalitzar l'execució del fil

Un cop s'inicien els fils, el programa actual (pots pensar-hi com un fil principal) també continua executant-se. Per aturar l'execució del programa actual fins que es completi un fil, fem servir el uneix-te () mètode.

t1.join() t2.join()>

Com a resultat, el programa actual s'esperarà primer que finalitzi t1 i llavors t2 . Un cop s'han acabat, s'executen les sentències restants del programa actual.

Exemple:

Considerem un exemple senzill amb un mòdul de threading.

Aquest codi mostra com utilitzar el mòdul de fils de Python per calcular el quadrat i el cub d'un nombre simultàniament. Dos fils, t1> i t2> , es creen per realitzar aquests càlculs. S'inicien i els seus resultats s'imprimeixen en paral·lel abans que el programa imprimeixi Fet! quan els dos fils hagin acabat. El threading s'utilitza per aconseguir el paral·lelisme i millorar el rendiment del programa quan es tracta de tasques intensives en càlcul.

Python 3




import> threading> def> print_cube(num):> >print>(>'Cube: {}'> .>format>(num>*> num>*> num))> def> print_square(num):> >print>(>'Square: {}'> .>format>(num>*> num))> if> __name__>=>=>'__main__'>:> >t1>=> threading.Thread(target>=>print_square, args>=>(>10>,))> >t2>=> threading.Thread(target>=>print_cube, args>=>(>10>,))> >t1.start()> >t2.start()> >t1.join()> >t2.join()> >print>(>'Done!'>)>

>

>

Sortida:

matrius de programació java
Square: 100 Cube: 1000 Done!>

Considereu el diagrama següent per entendre millor com funciona el programa anterior:

multithreading-python-4

Multithreading

Exemple:

En aquest exemple, fem servir os.getpid() funció per obtenir l'ID del procés actual. Fem servir threading.main_thread() funció per obtenir l'objecte del fil principal. En condicions normals, el fil principal és el fil des del qual es va iniciar l'intèrpret de Python. nom l'atribut de l'objecte fil s'utilitza per obtenir el nom del fil. Després fem servir el threading.current_thread() funció per obtenir l'objecte de fil actual.

Considereu el programa Python que es mostra a continuació en el qual imprimim el nom del fil i el procés corresponent per a cada tasca.

j e s t

Aquest codi mostra com utilitzar el mòdul de fils de Python per executar dues tasques simultàniament. El programa principal inicia dos fils, t1> i t2> , cadascun encarregat d'executar una tasca concreta. Els fils s'executen en paral·lel i el codi proporciona informació sobre l'ID del procés i els noms dels fils. Elos>El mòdul s'utilitza per accedir a l'ID del procés i al threading'> El mòdul s'utilitza per gestionar els fils i la seva execució.

Python 3




import> threading> import> os> def> task1():> >print>(>'Task 1 assigned to thread: {}'>.>format>(threading.current_thread().name))> >print>(>'ID of process running task 1: {}'>.>format>(os.getpid()))> def> task2():> >print>(>'Task 2 assigned to thread: {}'>.>format>(threading.current_thread().name))> >print>(>'ID of process running task 2: {}'>.>format>(os.getpid()))> if> __name__>=>=> '__main__'>:> >print>(>'ID of process running main program: {}'>.>format>(os.getpid()))> >print>(>'Main thread name: {}'>.>format>(threading.current_thread().name))> >t1>=> threading.Thread(target>=>task1, name>=>'t1'>)> >t2>=> threading.Thread(target>=>task2, name>=>'t2'>)> >t1.start()> >t2.start()> >t1.join()> >t2.join()>

>

>

Sortida:

ID of process running main program: 1141 Main thread name: MainThread Task 1 assigned to thread: t1 ID of process running task 1: 1141 Task 2 assigned to thread: t2 ID of process running task 2: 1141>

El diagrama que es mostra a continuació aclareix el concepte anterior:

multithreading-python-5

Multithreading

Per tant, aquesta va ser una breu introducció al multithreading a Python. El següent article d'aquesta sèrie cobreix sincronització entre diversos fils . Multithreading en Python | Conjunt 2 (sincronització)

Pool de fils de Python

Un grup de fils és una col·lecció de fils que es creen per endavant i que es poden reutilitzar per executar diverses tasques. El mòdul concurrent.futures de Python proporciona una classe ThreadPoolExecutor que facilita la creació i gestió d'un grup de fils.

En aquest exemple, definim un treballador de funció que s'executarà en un fil. Creem un ThreadPoolExecutor amb un màxim de 2 fils de treball. A continuació, enviem dues tasques al grup mitjançant el mètode d'enviament. El grup gestiona l'execució de les tasques en els seus fils de treball. Utilitzem el mètode de tancament per esperar que s'acabin totes les tasques abans que continuï el fil principal.

El multithreading us pot ajudar a fer que els vostres programes siguin més eficients i sensibles. Tanmateix, és important anar amb compte quan es treballa amb fils per evitar problemes com ara les condicions de carrera i els bloquejos.

Aquest codi utilitza un grup de fils creat amb concurrent.futures.ThreadPoolExecutor> per executar dues tasques de treball simultàniament. El fil principal espera que els fils de treball s'acabin d'utilitzar pool.shutdown(wait=True)> . Això permet un processament paral·lel eficient de les tasques en un entorn multiprocés.

Python 3




import> concurrent.futures> def> worker():> >print>(>'Worker thread running'>)> pool>=> concurrent.futures.ThreadPoolExecutor(max_workers>=>2>)> pool.submit(worker)> pool.submit(worker)> pool.shutdown(wait>=>True>)> print>(>'Main thread continuing to run'>)>

>

instanceof en java
>

Sortida

Worker thread running Worker thread running Main thread continuing to run>