이 글은 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!