Heim  >  Artikel  >  Backend-Entwicklung  >  Tiefes Verständnis der Coroutine-Funktionen in Python

Tiefes Verständnis der Coroutine-Funktionen in Python

零到壹度
零到壹度Original
2018-04-14 11:16:161737Durchsuche

Der Inhalt dieses Artikels soll Ihnen ein tiefgreifendes Verständnis der Coroutine-Funktion in Python vermitteln. Er hat einen gewissen Referenzwert.

Konzept:

Gemäß der Definition von Wikipedia sind „Coroutinen Computerprogrammkomponenten, die Unterroutinen für nicht-präemptives Multitasking generieren. Coroutinen ermöglichen es verschiedenen Einstiegspunkten, die Programmausführung an verschiedenen Orten anzuhalten oder zu starten.“ Aus technischer Sicht ist „eine Coroutine eine Funktion, deren Ausführung man anhalten kann.“ Wenn Sie es als „wie einen Generator“ verstehen, dann denken Sie richtig.

Coroutine, auch bekannt als Micro-Thread , sieht aus wie eine Unterroutine, kann aber während der Ausführung die aktuelle Unterroutine unterbrechen Bei anderen Unterprogrammen kehrt es zurück, um das vorherige Unterprogramm auszuführen, die zugehörigen Informationen sind jedoch immer noch dieselben wie zuvor.

Coroutinen unterscheiden sich von Threads Threads sind präventive Planung, während Coroutinen eine kollaborative Planung sind.
Unterprogrammaufrufe haben immer einen Eingang und einen Rücksprung, und die Aufrufreihenfolge ist klar. Der Aufruf von Coroutinen unterscheidet sich vom Aufruf von Unterprogrammen. Coroutinen sehen auch wie Unterprogramme aus, aber während der Ausführung können sie innerhalb des Unterprogramms unterbrochen werden, dann zur Ausführung anderer Unterprogramme wechseln und dann zu gegebener Zeit zurückkehren, um die Ausführung fortzusetzen.

Vorteile von Coroutinen:

  • Der Vorteil von Coroutinen ist eine extrem hohe Ausführungseffizienz. Da das Wechseln von Unterprogrammen kein Thread-Wechsel ist, sondern vom Programm selbst gesteuert wird, entsteht beim Thread-Wechsel kein Overhead. Im Vergleich zum Multithreading sind die Leistungsvorteile von Coroutinen umso offensichtlicher, je größer die Anzahl der Threads ist. Es eignet sich sehr gut für die Durchführung von Coroutine-Multitasking.

  • Coroutinen haben keine Thread-Sicherheitsprobleme. Ein Prozess kann mehrere Coroutinen gleichzeitig haben, aber nur eine Coroutine ist aktiv, und die Aktivierung und Ruhephase von Coroutinen wird vom Programmierer durch Programmierung gesteuert, nicht vom Betriebssystem.

Generator implementiert das Coroutine-Prinzip

Beispiel:

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

Erklärung:

  • Offensichtlich ist func ein Generator und die send-Methode verfügt über einen Parameter, der den Rückgabewert der zuletzt angehaltenen yield-Anweisung angibt.

  • send muss Ausnahmen behandeln.

  • Im Allgemeinen besteht der einzige Unterschied zwischen der Sendemethode und der nächsten Methode darin, dass beim Ausführen der Sendemethode zunächst der Rückgabewert der letzten ausstehenden Yield-Anweisung über Parameter auf festgelegt wird Interaktion mit Generatormethoden erreichen. Es ist jedoch zu beachten, dass vor der Ausführung der nächsten Methode durch ein Generatorobjekt ein Fehler beim Ausführen der Sendemethode gemeldet wird, da keine Yield-Anweisung angehalten wird.

  • Wenn der Parameter der Sendemethode None ist, entspricht er vollständig der nächsten Methode.

Der Generator implementiert die Produzenten- und Konsumentenmuster:

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

Erklärung:

im Produzenten Führen Sie zuerst c.send(None) aus. Der Zweck besteht darin, den Verbraucher zuerst auflegen zu lassen und dann mit send den Wert zu übergeben. Beim ersten Übergeben von 1 gibt der Verbraucher 1 aus. Der Produzent gibt r nach dem Verbraucher aus. Wert.

Einführung von Greenlet

Obwohl CPython (Standard-Python) Coroutinen über Generatoren implementieren kann, ist die Verwendung nicht sehr praktisch.

Gleichzeitig implementiert Stackless Python, ein Derivat von Python, native Coroutinen, was bequemer zu verwenden ist.

Also begannen alle, den Coroutine-Code in Stackless herauszunehmen und ihn in ein CPython-Erweiterungspaket umzuwandeln.

Dies ist der Ursprung von Greenlet, also ist Greenlet eine C-Erweiterungsbibliothek, die native Coroutinen auf der untersten Ebene implementiert.

Codediagramm:

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-Wert:

  • Hochleistungsnative Coroutine

  • Explizites Umschalten mit klarerer Semantik

  • Funktionen direkt in Coroutinen einbinden und dabei den ursprünglichen Codestil beibehalten

Gevent-Coroutine

Obwohl wir ein auf Epoll basierendes Callback-Programmiermodell haben, ist es schwierig zu verwenden.

Auch wenn wir Generator-Coroutinen verwenden können, um komplexe Kapselungen durchzuführen und Programmierschwierigkeiten zu vereinfachen.
Aber es gibt immer noch ein großes Problem: Die Kapselung ist schwierig und der vorhandene Code muss

gevent fast vollständig neu geschrieben werden, indem die beiden Bibliotheken libev (basierend auf Epoll) und Greenlet gekapselt werden.
Helfen Sie uns, es zu kapseln, und ermöglichen Sie uns, Coroutinen threadartig zu verwenden.

Damit wir die Leistungsfähigkeit von Epoll und Coroutinen voll ausschöpfen können, ohne den Originalcode neu schreiben zu müssen.

Codediagramm:

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 启动协程,参数就是函数的名字

Der Wert von gevent:

Wechseln Sie bei Blockierung zu einer anderen Coroutine. Fahren Sie fort und Mach es!

  • Verwenden Sie Epoll-basiertes Libev, um Blockierungen zu vermeiden.

  • Verwenden Sie eine effiziente Coroutine basierend auf Gevent, um die Ausführung zu wechseln.

  • Schaltet nur um, wenn eine Blockade auftritt. Es gibt keinen Round-Robin-Overhead oder Thread-Overhead.

gevent implementiert gleichzeitigen Server

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-Coroutine-Kommunikation

gevent verfügt auch über eine eigene Warteschlange. Die Verwendung ist im Grunde die gleiche wie beim Einfädeln.

Produzenten- und Verbrauchermuster basierend auf Gevent und Warteschlange

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 协程示例

Das obige ist der detaillierte Inhalt vonTiefes Verständnis der Coroutine-Funktionen in Python. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn