>  기사  >  백엔드 개발  >  Python에서 코루틴과 동시성을 어떻게 사용합니까?

Python에서 코루틴과 동시성을 어떻게 사용합니까?

青灯夜游
青灯夜游원래의
2018-09-21 15:19:552564검색

이 장에서는 Python의 코루틴 사용과 동시성을 소개하여 코루틴 사용의 장단점과 gevent 동시성 프레임워크의 역할을 이해할 수 있습니다. 도움이 필요한 친구들이 참고할 수 있기를 바랍니다.

Coroutine

Coroutine은 마이크로 스레드라고도 알려진 사용자 모드의 경량 스레드입니다.

코루틴에는 자체 레지스터 컨텍스트와 스택이 있습니다. 일정이 전환되면 레지스터 컨텍스트와 스택이 다른 곳에 저장됩니다. 다시 전환하면 이전에 저장된 레지스터 컨텍스트와 스택이 복원됩니다. 따라서 코루틴은 마지막 호출 상태(즉, 모든 로컬 상태의 특정 조합)를 유지할 수 있습니다. 프로세스가 다시 들어갈 때마다 이는 마지막 호출 상태로 들어가는 것과 같습니다. 마지막으로 떠난 상태입니다. 논리적 흐름의 위치입니다.

장점:

  1. 스레드 컨텍스트 전환의 오버헤드 없음

  2. 원자적 작업 잠금 및 동기화의 오버헤드 없음

  3. 제어 흐름의 편리한 전환, 단순화된 프로그래밍 모델

  4. 높은 동시성 + 높은 확장성 + 낮음 비용: CPU가 수만 개의 코루틴을 지원하는 것은 문제가 되지 않습니다. 따라서 높은 동시성 처리에 매우 적합합니다.

소위 원자 작업은 스레드 예약 메커니즘에 의해 중단되지 않는 작업을 의미합니다. 이 작업이 시작되면 중간에 컨텍스트 전환(다른 스레드로 전환) 없이 끝까지 실행됩니다.

원자적 연산은 한 단계일 수도 있고 여러 단계일 수도 있지만 순서가 중단될 수 없거나 실행된 부분만 끊어질 수 있습니다. 전체를 보는 것이 원자성의 핵심입니다.

단점:

  1. 멀티 코어 리소스를 활용할 수 없음: 코루틴의 본질은 단일 CPU의 여러 코어를 동시에 사용할 수 없습니다. 물론 우리의 일상생활에서는 CPU 집약적인 애플리케이션이 아닌 이상 작성된 대부분의 애플리케이션에는 이것이 필요하지 않습니다.

  2. 차단 작업(예: IO)을 수행하면 전체 프로그램이 차단됩니다.

Gevent 사용

gevent는 epoll을 사용하는 마이크로 스레드 greenlet을 핵심으로 하는 Python의 동시성 프레임워크입니다. 청취 메커니즘 및 기타 여러 최적화를 통해 효율적으로 작동합니다.:

  • 간단한 예

gevent의 절전 모드는 네트워크나 IO에 의해 제한되는 기능에서 gevent를 사용하면 이러한 기능이 공동으로 예약됩니다. gevent는 사실입니다. 역량이 발휘될 것입니다. Gevent는 가능한 경우 네트워크 라이브러리가 묵시적으로 greenlet 컨텍스트에 실행 권한을 넘겨줄 수 있도록 모든 세부 사항을 처리합니다.

import gevent
 
def foo():
    print('running in foo')
    gevent.sleep(0)
    print('com back from bar in to foo')
 
def bar():
    print('running in bar')
    gevent.sleep(0)
    print('com back from foo in to bar')
 
# 创建线程并行执行程序
gevent.joinall([
    gevent.spawn(foo),
    gevent.spawn(bar),
])

실행 결과:

Python에서 코루틴과 동시성을 어떻게 사용합니까?

  • 동기 및 비동기

import random
import gevent
 
def task(pid):
    gevent.sleep(random.randint(0, 2) * 0.001)
    print('Task %s done' % pid)
 
def synchronous():
    for i in range(1, 10):
        task(i)
 
def asynchronous():
    threads = [gevent.spawn(task, i) for i in range(10)]
    gevent.joinall(threads)
 
print('Synchronous:')
synchronous()
 
print('Asynchronous:')
asynchronous()

실행 출력:

Python에서 코루틴과 동시성을 어떻게 사용합니까?

  • 서브클래스 메서드에서 코루틴 사용

Greenlet 클래스, Overload 클래스를 서브클래싱할 수 있습니다. 다중 스레드 및 다중 프로세스 모듈과 유사한 _run 메소드

import gevent
from gevent import Greenlet
 
class Test(Greenlet):
 
    def __init__(self, message, n):
        Greenlet.__init__(self)
        self.message = message
        self.n = n
 
    def _run(self):
        print(self.message, 'start')
        gevent.sleep(self.n)
        print(self.message, 'end')
 
tests = [
    Test("hello", 3),
    Test("world", 2),
]
 
for test in tests:
    test.start()  # 启动
 
for test in tests:
    test.join()  # 等待执行结束
  • monkey 패치를 사용하여 시스템 표준 라이브러리를 수정합니다(자동으로 코루틴 전환)

greenlet이 네트워크 액세스와 같은 IO 작업을 발견할 때 , 자동으로 다른 Greenlet으로 전환하고 IO 작업이 완료될 때까지 기다린 다음 다시 전환하여 적절한 시간에 실행을 계속합니다.

IO 작업은 시간이 많이 걸리기 때문에 프로그램이 대기 상태로 남아 있는 경우가 많습니다. gevent가 자동으로 코루틴을 전환하면 IO를 기다리는 대신 Greenlet이 항상 실행되는 것이 보장됩니다.

IO 작업 중에 전환이 자동으로 완료되므로 gevent는 Python과 함께 제공되는 일부 표준 라이브러리를 수정해야 합니다. 이 프로세스는 시작 시 원숭이 패치를 통해 완료됩니다.

import gevent
import requests
from gevent import monkey
 
monkey.patch_socket()
 
def task(url):
    r = requests.get(url)
    print('%s bytes received from %s' % (len(r.text), url))
 
gevent.joinall([
    gevent.spawn(task, 'https://www.baidu.com/'),
    gevent.spawn(task, 'https://www.qq.com/'),
    gevent.spawn(task, 'https://www.jd.com/'),
])

실행 출력:

Python에서 코루틴과 동시성을 어떻게 사용합니까?

3개를 볼 수 있습니다. 두 개의 네트워크 작업이 동시에 실행되고 다른 순서로 종료됩니다

위 내용은 Python에서 코루틴과 동시성을 어떻게 사용합니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

관련 기사

더보기