Python의 동시성 차이

Python이 이러한 개념이나 기능을 이제 막 도입했다고 생각할 수도 있습니다. Python 3의 출시와 함께 비동기 작업 및 동시성의 새로운 추세에 대해 많이 들었기 때문입니다.

많은 초보자는 asyncio를 사용하는 것이 동시 및 비동기 활동을 수행하는 유일한 실용적인 방법이라고 생각할 수 있습니다. 이 기사에서는 Python에서 동시성을 달성하는 방법과 이점 또는 단점에 대해 설명합니다.

스레드 및 멀티스레딩

스레드는 파이썬에서 오랫동안 사용되어 왔습니다. 따라서 스레드의 존재로 인해 동시에 여러 작업을 수행할 수 있습니다.

불행하게도 Python의 일반적인 메인라인 버전인 CPython은 여전히 ​​GIL(Global Interpreter Lock)을 사용합니다. 이는 오늘날 병렬 처리를 달성하는 일반적인 방법인 멀티스레드 애플리케이션을 차선책으로 만듭니다.

Python은 C(예: 확장)와의 통합을 위해 CPython의 메모리 처리를 보다 쉽게 ​​관리할 수 있도록 GIL을 도입했습니다.

GIL은 잠금 메커니즘입니다. 즉, Python 인터프리터는 한 번에 하나의 스레드만 실행할 수 있습니다. Python의 바이트 코드는 한 번에 하나의 스레드에서만 실행할 수 있습니다.

샘플 코드:

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!")

산출:

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.

프로세스 및 다중 프로세스

다중 처리는 많은 CPU를 사용합니다. 각 CPU가 병렬로 실행되기 때문에 동시에 여러 작업을 효율적으로 실행할 수 있습니다. 이러한 CPU 바운드 작업의 경우 다중 처리를 사용하려는 것입니다.

Python은 병렬화를 달성하기 위해 multiprocessing 모듈을 도입했습니다. 스레드를 사용해 본 적이 있다면 매우 유사하게 느껴질 것입니다.

샘플 코드:

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")

산출:

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.

멀티스레딩 대신 CPU의 서로 다른 코어에서 여러 프로세스를 실행하면 Python 스크립트가 더 빨라집니다.

비동기 및 asyncio

동기식 작업에서 작업은 차례로 동기식으로 수행됩니다. 그러나 비동기 작업에서는 작업이 서로 완전히 독립적으로 시작될 수 있습니다.

실행이 다른 활동으로 전환되는 동안 비동기 작업이 시작되고 계속 실행될 수 있습니다. 반면에 비동기 작업은 차단하지 않고 백그라운드에서 실행되는 경우가 많습니다(실행자가 완료될 때까지 기다리게 함).

다른 중요한 기능 중에서 asyncio는 이벤트 루프를 제공합니다. 이벤트 루프는 다양한 I/O 이벤트를 모니터링하고 준비된 작업으로 전환하며 I/O를 기다리는 작업을 일시 중단합니다.

따라서 우리는 미완성 프로젝트에 시간을 낭비하지 않습니다.

샘플 코드:

#Python小白学习交流群:711312441
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()

위의 코드 스니펫을 살펴보면 다음과 같습니다.

  • 숫자와 이벤트 루프를 매개 변수로 사용하는 비동기 함수 displayDate가 있습니다.
  • 위의 함수에는 60초 후에 중지되는 무한 루프가 있습니다. 그러나 그 60초 동안 반복적으로 시간을 인쇄하고 스누즈합니다.
  • await 함수는 다른 비동기 함수가 완료될 때까지 기다릴 수 있습니다.
  • 이 함수를 이벤트 루프에 전달합니다(sure_future 함수 사용).
  • 이벤트 루프 실행을 시작합니다.

await가 호출될 때마다 asyncio는 함수가 시간이 걸릴 수 있음을 이해합니다. asyncio는 I/O가 중지된 기능에 대해 준비되었음을 알게 되면 프로세스를 다시 시작합니다.

이제 문제는 이 세 가지 형태의 동시성 중 어떤 것을 사용해야 하느냐입니다. 결정하는 데 도움이 되는 다음 사항을 확인할 수 있습니다.

  • CPU 바인딩 작업에 다중 처리를 사용합니다.
  • I/O Bound, 빠른 I/O 및 제한된 연결에 멀티스레딩을 사용합니다.
  • I/O 바운드, 느린 I/O 및 많은 연결의 경우 비동기 IO를 사용하십시오.
  • asyncio/await는 Python 3.5 이상에서 작동합니다.

다음 의사 코드를 참조할 수도 있습니다.

if io_bound:
    if io_very_slow:
        print("Use asyncio")
    else:
        print("Use multithreading")
else:
    print("multiprocessing")

Supongo que te gusta

Origin blog.csdn.net/qdPython/article/details/132045413
Recomendado
Clasificación