Python의 코루틴 함수에 대한 깊은 이해

零到壹度
풀어 주다: 2018-04-14 11:16:16
원래의
1720명이 탐색했습니다.

이 글의 내용은 파이썬의 코루틴 함수에 대한 심층적인 이해를 공유하기 위한 것입니다. 여기에는 특정 참조 값이 있습니다. 도움이 필요한 친구는 이를 참조할 수 있습니다.

개념:

주어진 정의에 따라 Wikipedia에 따르면 "코루틴" 루틴은 비선점형 멀티태스킹을 위한 서브루틴을 생성하는 컴퓨터 프로그램 구성 요소입니다. 코루틴을 사용하면 다양한 진입점을 통해 다양한 위치에서 프로그램 실행을 일시 중지하거나 시작할 수 있습니다. 기술적 관점에서 보면 "코루틴은 실행을 일시 중지할 수 있는 함수입니다." "제너레이터와 같다"고 이해하셨다면, 올바른 생각을 하신 것입니다.

마이크로 스레드라고도 알려진 코루틴은 서브루틴처럼 보이지만 실행 프로세스 중에 현재 서브루틴을 중단하고 다른 서브루틴을 실행한 다음 돌아와서 이전 서브루틴을 실행할 수 있습니다. 서브루틴이지만 관련 정보는 이전과 동일합니다.

코루틴은 스레드와 다릅니다. 스레드는 선점형 스케줄링인 반면 코루틴은 자체 스케줄링을 수행해야 합니다.
서브루틴 호출에는 항상 하나의 진입과 하나의 복귀가 있으며 호출 순서가 명확합니다. 코루틴 호출은 서브루틴과 다릅니다. 코루틴도 서브프로그램처럼 보이지만 실행 중에 서브프로그램 내에서 중단될 수 있으며, 다른 서브프로그램 실행으로 전환한 다음 적절한 시간에 다시 실행을 계속할 수 있습니다.

코루틴의 장점:

  • 코루틴의 장점은 실행 효율성이 매우 높다는 것입니다. 서브루틴 전환은 스레드 전환이 아니라 프로그램 자체에 의해 제어되므로 스레드 전환에 따른 오버헤드가 없습니다. 멀티스레딩에 비해 스레드 수가 많을수록 코루틴의 성능 이점은 더욱 분명해집니다. 코루틴 멀티태스킹을 수행하는 데 매우 적합합니다.

  • 코루틴에는 스레드 안전 문제가 없습니다. 프로세스는 동시에 여러 개의 코루틴을 가질 수 있지만 단 하나의 코루틴만 활성화되며 코루틴의 활성화 및 최대 절전 모드는 운영 체제가 아닌 프로그래밍을 통해 프로그래머에 의해 제어됩니다.

Generator는 코루틴 원칙을 구현합니다.

예:

def func(n):
    index=0
    if index<=n:
        c=yield 1
        print("task------{}".format(c))
        index+=1f=func(3)
n=next(f)
print(n)try:
    n=f.send(5)#程序就直接结束了
    print("n是{}".format(n))except StopIteration as e:    pass
로그인 후 복사
输出打印:1task------5
로그인 후 복사

설명:

  • 분명히 func는 생성기이고 send 메소드에는 마지막 보류 중인 Yield 명령문의 반환 값을 지정하는 매개변수가 있습니다.

  • send는 예외를 처리해야 합니다.

  • 일반적으로 send 메서드와 next 메서드의 유일한 차이점은 send 메서드를 실행할 때 마지막 보류 중인 Yield 문의 반환 값이 먼저 매개 변수를 통해 설정되어 생성기 메서드와의 상호 작용을 달성한다는 것입니다. 하지만 제너레이터 객체가 다음 메소드를 실행하기 전에는 어떠한 Yield 문도 정지되지 않았기 때문에 send 메소드를 실행하면 오류가 보고된다는 점에 유의해야 합니다.

  • send 메소드의 매개변수가 None이면 다음 메소드와 완전히 동일합니다.

생성기는 생산자와 소비자 패턴을 구현합니다.

def cunsumer():
    while True:
        n=yield 3
        if not n:            return
        print(&#39;cunsumer{}&#39;.format(n))def product(c):
    c.send(None)
    n=0
    while n<5:
        n=n+1
        r=c.send(n)
        print("product{}".format(r))
    c.close()
c=cunsumer()
product(c)
로그인 후 복사
打印:
cunsumer1
product3
cunsumer2
product3
cunsumer3
product3
cunsumer4
product3
cunsumer5
product3
로그인 후 복사

설명:

c.send(None)는 생산자에서 먼저 실행됩니다. 목적은 소비자가 먼저 전화를 끊도록 한 다음 send를 사용하는 것입니다. Pass 값, 처음 1이 전달되면 소비자는 1을 인쇄하고 생산자는 소비자의 Yield 이후 값인 r을 인쇄합니다.

greenlet 소개

CPython(표준 Python)은 생성기를 통해 코루틴을 구현할 수 있지만 사용하기가 그리 편리하지는 않습니다.

동시에 Python의 파생인 Stackless Python은 사용하기 더 편리한 네이티브 코루틴을 구현합니다.

그래서 다들 스택리스에서 코루틴 코드를 꺼내어 CPython 확장 패키지로 만들기 시작했습니다.

이것이 Greenlet의 유래이므로 Greenlet은 하단에 네이티브 코루틴을 구현한 C 확장 라이브러리입니다.

코드 다이어그램:

from greenlet import greenletimport randomimport timedef Producer():
    while True:
        item = random.randint(0,10)
        print("生产了{}".format(item))
        c.switch(item)#切换到消费者,并将item传入消费者
        time.sleep(1)def consumer():
    print(&#39;我先执行&#39;)    #p.switch()
    while True:
        item = p.switch()#切换到生产者,并且等待生产者传入item
        print(&#39;消费了{}&#39;.format(item))
c = greenlet(consumer)#将一个普通函数变成一个协程p = greenlet(Producer)
c.switch()#让消费者先进入暂停状态(只有恢复了才能接收数据)
로그인 후 복사

greenlet 값:

  • 고성능 네이티브 코루틴

  • 더 명확한 의미로 명시적 전환

  • 원본 코드를 유지하면서 함수를 코루틴으로 직접 래핑 스타일

gevent coroutine

epoll을 기반으로 한 콜백 프로그래밍 모델이 있지만 사용하기가 어렵습니다.

생성기 코루틴을 사용하여 복잡한 캡슐화를 수행하여 프로그래밍 어려움을 단순화할 수 있다고 해도 말이죠.
하지만 여전히 큰 문제가 있습니다. 캡슐화가 어렵고 두 라이브러리 libev(epoll 기반)와 greenlet을 캡슐화하여 기존 코드를 거의 완전히 다시 작성해야 합니다

gevent.
코루틴을 캡슐화하고 스레드와 같은 방식으로 코루틴을 사용할 수 있도록 도와주세요.

원래 코드를 다시 작성하지 않고도 epoll과 코루틴의 기능을 완전히 활용할 수 있을 만큼 너무 많습니다.

코드 다이어그램:

from gevent import monkey;monkey.patch_all()#会把python标准库当中一些阻塞操作变成非阻塞import geventdef test1():
    print("11")
    gevent.sleep(4)#模拟爬虫请求阻塞
    print("33")def test2():
    print("22")
    gevent.sleep(4)
    print("44")
gevent.joinall([gevent.spawn(test1),gevent.spawn(test2)])#joinall 阻塞当前协程,执行给定的greenlet#spawn 启动协程,参数就是函数的名字
로그인 후 복사

gevent 값:

막힘이 발생하면 다른 코루틴으로 전환하여 실행을 계속하세요!

  • 차단을 방지하려면 epoll 기반 libev를 사용하세요.

  • gevent를 기반으로 한 효율적인 코루틴을 사용하여 실행을 전환하세요.

  • 막힘이 발생할 때만 전환합니다. 라운드 로빈 오버헤드나 스레드 오버헤드는 없습니다.

gevent는 동시 서버를 구현합니다

from gevent import monkey;monkey.patch_all()  #建议放在首行,会把python标准库当中一些阻塞操作变成非阻塞import geventimport socket


server=socket.socket()
server.bind((&#39;&#39;,6666))
server.listen(5)
print("开始监听")def readable(con,addr):
    print("客户端{}接入".format(addr))    while True:
        data=con.recv(1024)        if data:
            print(data)        else:
            con.close()            breakwhile True:
    con,addr=server.accept()
    gevent.spawn(readable,con,addr)#将readable函数变为协程,并且把con和addr传入其中。
로그인 후 복사

gevent 코루틴 통신

gevent에는 자체 대기열도 있습니다. 사용법은 기본적으로 스레딩과 동일합니다.

gevent 및 대기열을 기반으로 한 생산자 및 소비자 패턴

from gevent import monkey;monkey.patch_all()import geventfrom gevent.queue import Queueimport randomdef producter(queue):
    while True:
        item=random.randint(0,99)
        print(&#39;生产了{}&#39;.format(item))
        queue.put(item)
        gevent.sleep(1)def comuser(queue):
    while True:
        item=queue.get()
        print(&#39;消费了{}&#39;.format(item))
queue=Queue()
p=gevent.spawn(producter,queue)
c=gevent.spawn(comuser,queue)
gevent.joinall([p,c])
로그인 후 복사
打印:
生产了33消费了33生产了95消费了95生产了92消费了92...
로그인 후 복사


相关推荐:

python中多进程+协程的使用

python中协程

Python 协程的详细用法和例子

python 协程示例

위 내용은 Python의 코루틴 함수에 대한 깊은 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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