Unterschied in Parallelitätsaspekten in Python

Unterschied in Parallelitätsaspekten in Python

Man kann sich vorstellen, dass Python diese Begriffe oder Fähigkeiten gerade erst eingeführt hat, da wir mit der Veröffentlichung von Python 3 viele neue Trends in Bezug auf asynchrone Operationen und Parallelität hören.

Viele Neulinge glauben vielleicht, dass die Verwendung von asyncio der einzige praktische Ansatz zur Durchführung gleichzeitiger und asynchroner Aktivitäten ist. In diesem Artikel wird erläutert, wie wir Nebenläufigkeit und ihre Vor- und Nachteile in Python erreichen können.

Threads und Multithreading

Threads gibt es schon sehr lange in Python. Infolgedessen können wir dank Threads mehrere Operationen gleichzeitig ausführen.

Leider verwendet CPython, eine typische Mainline-Python-Version, immer noch die globale Interpreter-Sperre (GIL), was Multi-Thread-Anwendungen – die heutzutage übliche Methode zur Implementierung von Parallelverarbeitung – alles andere als ideal macht.

Python hat GIL eingeführt, um die Speicherverwaltung von CPython für Integrationen mit C (z. B. die Erweiterungen) besser handhabbar zu machen.

Die GIL ist ein Verriegelungsmechanismus, bei dem der Python-Interpreter nur einen Thread gleichzeitig ausführt. Pythons byte-Code kann immer nur von einem Thread gleichzeitig ausgeführt werden.

Beispielcode:

import threading
import time
import random


def worker(num):
    sec = random.randrange(1, 5)
    time.sleep(sec)
    print("I am thread {}, who slept for {} seconds.".format(num, sec))


for i in range(3):
    t = threading.Thread(target=worker, args=(i,))
    t.start()

print("Completed!")

Ausgang:

Completed!
I am thread 1, who slept for 3 seconds.
I am thread 3, who slept for 2 seconds.
I am thread 4, who slept for 4 seconds.

Prozesse und Multiprocessing

Multiprocessing nutzt viele CPUs. Wir können effektiv mehrere Aufgaben gleichzeitig ausführen, da jede CPU parallel arbeitet. Für Jobs, die CPU-gebunden sind, ist Multiprocessing das, was Sie verwenden möchten.

Python führt das multiprocessing-Modul ein, um Parallelität zu erreichen, was sich sehr ähnlich anfühlen wird, wenn Sie Threading verwendet haben.

Beispielcode:

import multiprocessing
import time
import random


def worker(num):
    sec = random.randrange(1, 5)
    time.sleep(sec)
    print("I am process {}, who slept for {} seconds.".format(num, sec))


for i in range(3):
    t = multiprocessing.Process(target=worker, args=(i,))
    t.start()

print("Completed")

Ausgang:

Completed
I am process 1, who slept for 1 seconds.
I am process 2, who slept for 2 seconds.
I am process 0, who slept for 3 seconds.

Anstelle von Multithreading verwenden wir mehrere Prozesse, die auf verschiedenen Kernen Ihrer CPU ausgeführt werden, wodurch unser Python-Skript schneller wird.

Asynchron und asyncio

Beim synchronen Betrieb werden die Aufgaben synchron nacheinander ausgeführt. Jobs können jedoch völlig unabhängig voneinander in asynchronen Operationen beginnen.

Eine asynchrone Aufgabe kann gestartet und weiter ausgeführt werden, während die Ausführung zu einer anderen Aktivität wechselt. Andererseits werden asynchrone Aufgaben oft im Hintergrund ausgeführt und blockieren nicht (lassen Sie die Implementierung auf den Abschluss warten).

Neben weiteren wertvollen Features bietet asyncio eine Event-Schleife. Die Ereignisschleife überwacht verschiedene E/A-Ereignisse, schaltet auf bereite Aufgaben um und hält Aufgaben an, die auf E/A warten.

Daher verschwenden wir keine Zeit mit unvollendeten Projekten.

Beispielcode:

import asyncio
import datetime
import random


async def my_sleep_func():
    await asyncio.sleep(random.randint(0, 5))


async def displayDate(num, loop):
    endTime = loop.time() + 60.0
    while True:
        print("Loop: {} Time: {}".format(num, datetime.datetime.now()))
        if (loop.time() + 1.0) >= endTime:
            break
        await my_sleep_func()


loop = asyncio.get_event_loop()

asyncio.ensure_future(displayDate(1, loop))
asyncio.ensure_future(displayDate(2, loop))

loop.run_forever()

Wenn wir das obige Code-Snippet durchgehen:

  • Wir haben eine async-Funktion displayDate, die eine Zahl und die Event-Schleife als Parameter nimmt.
  • Die genannte Funktion hat eine Endlosschleife, die nach 60 Sekunden stoppt. Aber während dieser 60 Sekunden druckt es immer wieder die Uhrzeit aus und macht ein Nickerchen.
  • Die await-Funktion kann auf den Abschluss anderer async-Funktionen warten.
  • Wir übergeben die Funktion an die Ereignisschleife (mit der Funktion ensure_future).
  • Wir starten die Ereignisschleife.

Immer wenn der await-Aufruf gemacht wird, versteht asyncio, dass die Funktion wahrscheinlich einige Zeit brauchen wird. Wenn asyncio bemerkt, dass die E/A der angehaltenen Funktion bereit ist, setzt es den Prozess fort.

Nun, der Punkt ist, was müssen wir unter den drei Formen der Parallelität verwenden? Als Entscheidungshilfe können wir folgendes beachten:

  • Verwenden Sie Multiprocessing für CPU-gebundene Operationen.
  • Verwenden Sie Multithreading für I/O Bound, Fast I/O und Limited Number of Connections.
    – Verwenden Sie asynchrone E/A für E/A-gebundene, langsame E/A und viele Verbindungen.
  • asyncio/await funktioniert auf Python 3.5 und höher.

Wir können auch auf den folgenden Pseudocode verweisen:

if io_bound:
    if io_very_slow:
        print("Use asyncio")
    else:
        print("Use multithreading")
else:
    print("multiprocessing")
Marion Paul Kenneth Mendoza avatar Marion Paul Kenneth Mendoza avatar

Marion specializes in anything Microsoft-related and always tries to work and apply code in an IT infrastructure.

LinkedIn

Verwandter Artikel - Python Threading

Verwandter Artikel - Python Async