Python 코루틴에 대한 자세한 설명(예제 포함)

不言
풀어 주다: 2018-10-08 17:41:10
앞으로
5910명이 탐색했습니다.

이 글은 Python 코루틴에 대한 자세한 설명을 제공합니다(예제 포함). 도움이 필요한 친구들이 참고할 수 있기를 바랍니다.

프로세스와 스레드 간 전환에는 시간이 걸립니다. 다음에 실행을 계속하려면 스레드 프로세스의 현재 상태를 저장하세요. CPU를 많이 필요로 하지 않는 프로그램, 즉 IO 집약적인 프로그램에 비해 코루틴은 스레드 프로세스보다 리소스를 덜 소비하고 전환 속도가 빠르며 IO 집약적인 프로그램에 더 적합합니다. 코루틴 역시 싱글 스레드이므로 멀티 코어 CPU의 장점을 활용하지 못합니다. 멀티 코어 CPU의 장점을 활용하려면 프로세스 + 코루틴 또는 프로세스 + 스레드 + 코루틴의 방법을 사용할 수 있습니다.

1. 코루틴의 간단한 구현

코루틴의 원리는 생성기를 통해 다음과 같이 구현됩니다. 프로그램은 19번 라인까지 실행되고, 13번 라인까지 소비자 기능을 실행하고, 다음으로 제너레이터가 8번 라인까지 생산자 기능을 실행하고, 중지합니다. , 그리고 반환 소비자 함수는 라인 13에서 계속 실행되고 루프는 다시 라인 13에 도달합니다. 생성기 함수는 마지막 산출이 중지된 지점부터 실행됩니다. 이렇게 루프가 완료되면 동시성 효과가 완성됩니다.

그러나 어떤 사람들은 아래 두 번째 예와 같이 루프를 사용하여 두 가지 기능을 순차적으로 실행하면 결과가 동일하다고 말할 수 있습니다. 여기서 말하고 싶은 것은 함수의 실행 위치를 보존하지 않고 단순히 한 함수를 실행한 후 다른 함수로 전환할 뿐이며 CPU가 기다려야 하는 작업이 발생하면 전환할 수 없다는 것입니다. CPU를 기다려야 하는 작업이 발생하면 적극적으로 CPU를 포기하고 함수의 실행 위치를 기억한 후 다음 번에 다시 실행하도록 전환합니다. 이는 동시 작업으로 간주되어 프로그램의 동시성 효과를 향상시킬 수 있습니다.

코루틴은 단순히 생산자와 소비자를 구현합니다

import time
def producer():
    while True:
        time.sleep(1)
        print("+++++ 1个包子", time.strftime("%X"))
        yield
def consumer():
    while True:
        next(prd)
        print("----- 1个包子", time.strftime("%X"))
if __name__ == "__main__":
    prd = producer()
    consumer()
# 输出结果
+++++ 1个包子 16:22:30
----- 1个包子 16:22:30
+++++ 1个包子 16:22:31
----- 1个包子 16:22:31
+++++ 1个包子 16:22:32
----- 1个包子 16:22:32
+++++ 1个包子 16:22:33
----- 1个包子 16:22:33
로그인 후 복사

순차 실행 효과

import time
def producer():
    time.sleep(1)
    print("+++++ 1个包子", time.strftime("%X"))
def consumer():
    print("----- 1个包子", time.strftime("%X"))
if __name__ == "__main__":
    while True:
        producer()
        consumer()
# 输出结果
+++++ 1个包子 16:22:30
----- 1个包子 16:22:30
+++++ 1个包子 16:22:31
----- 1个包子 16:22:31
+++++ 1个包子 16:22:32
----- 1个包子 16:22:32
+++++ 1个包子 16:22:33
----- 1个包子 16:22:33
로그인 후 복사

2. greenlet

greenlet 모듈을 설치해야 합니다. pip install greenlet입니다. 그린렛 원리는 발전기를 캡슐화하는 것입니다. Greenlet 클래스는 전환 메소드를 제공합니다: 전환이 필요할 때 지정된 코루틴으로 전환합니다.

from greenlet import greenlet
import time
def producer():
    while True:
        time.sleep(1)
        print("+++++ 1个包子", time.strftime("%X"))
        gr2.switch()  # 切换到gr2运行
def consumer():
    while True:
        print("----- 1个包子", time.strftime("%X"))
        gr1.switch()  # 切换到gr1运行
if __name__ == "__main__":
    gr1 = greenlet(producer)
    gr2 = greenlet(consumer)
    gr1.switch()  # 切换到gr1运行
# 输出结果
+++++ 1个包子 09:39:45
----- 1个包子 09:39:45
+++++ 1个包子 09:39:46
----- 1个包子 09:39:46
+++++ 1个包子 09:39:47
----- 1个包子 09:39:47
로그인 후 복사

3.gevent

gevent 모듈도 설치해야 합니다. pip install gevent입니다. gevent는 시간이 많이 걸리는 작업을 자동으로 식별하고 다른 코루틴으로 전환할 수 있는 gevent를 다시 캡슐화한 것입니다. gevent는 시간이 많이 걸리는 작업이 발생할 때만 실행 중인 코루틴을 전환합니다. 시간이 많이 걸리는 작업이 발생하지 않으면 적극적으로 전환하지 않습니다.

gevent.spawn(*args, **kwargs) 가변 길이 매개변수의 첫 번째 매개변수는 코루틴이 실행하는 fn 메서드이고 나머지는 순서대로 fn의 매개변수입니다. 코루틴을 시작한 후 Join 메서드를 호출합니다.

gevent 모듈에서 시간이 많이 걸리는 작업을 식별하는 두 가지 방법이 있습니다. ① gevent 모듈에서 재정의된 클래스를 사용하세요. 예를 들어 gevent.socket gevent.sleep ② 패치 방법, 모든 코드 이전. ~에서 gevent import Monkey는 이 모듈을 가져오고, Monkey.patch_all()은 이 메서드를 호출합니다.

작성된 코드를 변경할 필요가 없도록 두 번째 방법을 사용하는 것이 좋습니다.

일반적인 상황에서는 gevent는 시간이 많이 걸리는 작업을 식별하지 않습니다.

import time
import gevent
def producer():
    for i in range(3):
        time.sleep(1)
        print("+++++ 1个包子", name, time.strftime("%X"))
def consumer():
    for i in range(3):
        time.sleep(1)
        print("----- 1个包子", name, time.strftime("%X"))
if __name__ == "__main__":
    g1 = gevent.spawn(producer, "zhangsan")
    g2 = gevent.spawn(consumer, "lisi")
    g1.join()
    g2.join()
# 输出结果
+++++ 1个包子 zhangsan 10:42:38
+++++ 1个包子 zhangsan 10:42:39
+++++ 1个包子 zhangsan 10:42:40
----- 1个包子 lisi 10:42:41
----- 1个包子 lisi 10:42:42
----- 1个包子 lisi 10:42:43
로그인 후 복사

gevent는 시간이 많이 걸리는 작업을 식별합니다. . 방법 1, gevent에 있는 모듈 사용

import time
import gevent
def producer():
    for i in range(3):
        gevent.sleep(1)
        print("+++++ 1个包子", time.strftime("%X"))
def consumer():
    for i in range(3):
        gevent.sleep(1)
        print("----- 1个包子", time.strftime("%X"))
if __name__ == "__main__":
    g1 = gevent.spawn(producer)
    g2 = gevent.spawn(consumer)
    g1.join()
    g2.join()
# 输出结果
+++++ 1个包子 10:43:04
----- 1个包子 10:43:04
+++++ 1个包子 10:43:05
----- 1个包子 10:43:05
+++++ 1个包子 10:43:06
----- 1个包子 10:43:06
로그인 후 복사

gevent는 시간이 많이 걸리는 작업 방법 2, 패치

import time
import gevent
from gevent import monkey
monkey.patch_all()
def producer():
    for i in range(3):
        time.sleep(1)
        print("+++++ 1个包子", time.strftime("%X"))
def consumer():
    for i in range(3):
        time.sleep(1)
        print("----- 1个包子", time.strftime("%X"))
if __name__ == "__main__":
    g1 = gevent.spawn(producer)
    g2 = gevent.spawn(consumer)
    g1.join()
    g2.join()
# 输出结果
+++++ 1个包子 10:44:04
----- 1个包子 10:44:04
+++++ 1个包子 10:44:05
----- 1个包子 10:44:05
+++++ 1个包子 10:44:06
----- 1个包子 10:44:06
로그인 후 복사

공개된 코루틴이 많을 경우 조인 메서드를 하나씩 호출하는 것이 약간 번거롭기 때문에 gevent에서 제공합니다. 한꺼번에 모든 코루틴을 조인할 수 있는 Joinall() 메소드. Joinall() 메서드는 모든 코루틴을 포함하는 목록을 전달합니다.

joinall

import time
import gevent
from gevent import monkey
monkey.patch_all()
def producer(name):
    for i in range(3):
        time.sleep(1)
        print("+++++ 1个包子", name, time.strftime("%X"))
def consumer(name):
    for i in range(3):
        time.sleep(1)
        print("----- 1个包子",  name, time.strftime("%X"))
if __name__ == "__main__":
    gevent.joinall([gevent.spawn(producer, "zhangsan"), gevent.spawn(consumer, "lisi")])
# 输出结果
+++++ 1个包子 zhangsan 10:51:34
----- 1个包子 lisi 10:51:34
+++++ 1个包子 zhangsan 10:51:35
----- 1个包子 lisi 10:51:35
+++++ 1个包子 zhangsan 10:51:36
----- 1个包子 lisi 10:51:36
로그인 후 복사

4. 코루틴 애플리케이션, 동시 서버

서버는 클라이언트 메시지를 받아서 그대로 돌려준다

server

import socket
import gevent
from gevent import monkey
monkey.patch_all()
def fn(conn):
    msg = conn.recv(1024).decode("utf-8")
    print("服务的收到>>>", msg)
    conn.send(msg.encode("utf-8"))
sk = socket.socket()
sk.bind(("127.0.0.1", 8899))
sk.listen()
while True:
    conn, addr = sk.accept()
    print("已连接服务器-->", addr)
    gevent.spawn(fn, conn)
sk.close()
# 输出结果
已连接服务器--> ('127.0.0.1', 53878)
已连接服务器--> ('127.0.0.1', 53879)
已连接服务器--> ('127.0.0.1', 53880)
服务的收到>>> client1
服务的收到>>> client2
服务的收到>>> client3
로그인 후 복사

clien

import socket
sk = socket.socket()
sk.connect(("127.0.0.1", 8899))
msg = input("客户端发送的内容>>> ")
sk.send(msg.encode("utf-8"))
msg = sk.recv(1024).decode("utf-8")
print("客户端收到>>>", msg)
sk.close()
# 输出结果
客户端发送的内容>>> client1
客户端收到>>> client1
로그인 후 복사

위 내용은 Python 코루틴에 대한 자세한 설명(예제 포함)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:cnblogs.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿