python network - to achieve the multi-task coroutine

First, coroutine

Coroutine, also called micro-threads, shred. English Coroutine.

Coroutine is not a process, not a thread, it is a function, a special function - can hang somewhere, and can be re-suspended in continues to run. So, coroutine with the process, compared to the thread, not one dimension of the concept.

A process can contain multiple threads, a thread can contain multiple coroutines, that is to say, there can be multiple special functions such as running within a thread. But one thing must be clear, a coroutine to run multiple threads within a serial. If you have multiple core CPU, then multiple processes or multiple threads within a process can be run in parallel, but more coroutines within a thread is definitely a serial, regardless of how many CPU (core). This is better understood, after all, although coroutine is a special function, but is still a function. You can run multiple functions within a single thread, but these functions are serial run. When a coroutine is running, other coroutine must be suspended.

Popular understanding: a function in a thread, you can save anywhere information about the current number of temporary variables function, and then switch to another function performed, not by way of calling attention to the function to do, and switching and when the number of times and then switch to the original function determined by the developers themselves

Learning Python junior partner, to learn the information can go to my micro-channel public number: learn Python circle, background replies: "01", you can take Python learning materials


16886563-8b1e78e67f1b77fd.png

Two, yield achieved coroutine

<pre class="prettyprint hljs python" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> 1 import time
2
3 def A():
4 while True:
5 print("----A---")
6 yield
7 time.sleep(0.3)
8
9 def B(c):
10 while True:
11 print("----B---")
12 next(c)
13 time.sleep(0.3)
14
15 if name=='main':
16 a = A()
17 B(a)
</pre>

Results of the

<pre class="prettyprint hljs lua" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">----B---
----A---
----B---
----A---
----B---
----A---
----B---
A --- ----
---- B ---
---- --- A
omitted. . .
</ pre>

Code Description:

Line 17: calling the function B, and put into a transmission. B performs printing of the code, the code is executed when the next (C), calls the function A, the execution code printing A, when the implementation of the code line 6 with a yield encounter implementation, the coroutine enters a wait state back to the original next (c) execution continues, thereby realizing a multi-switch coroutine through yield keyword.

Three, greenlet

1, greenlet multi-task coroutine

In order to better use the coroutine to complete the multi-task, the Python greenlet its module package, so that the task switching becomes easier, before use must first ensure that the module is installed greenlet

Use the following command module mounted greenlet:

<pre class="hljs nginx" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 0.75em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">sudo pip install greenlet
</pre>

<pre class="prettyprint hljs python" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">#coding = utf-8
from greenlet import greenlet
def test1():
print("1")
gr2.switch()
print("2")

def test2():
print("3")
gr1.switch()
print("4")

gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
</pre>

operation result:

When you create a greenlet, first initializes an empty stack, the stack switch to this time, will run in the incoming greenlet constructor (first printed in test1 in 1), if the switch on the function (test1) to the other coroutine (to print test2 3), then the coroutine will be suspended until the switch back (2 switch back print test1). When this function corresponds coroutine is finished, then the coroutine becomes dead state.

Note that the above is not the last line of print output test2 4, after switching to the suspend gr1 as in test2, but there is no place to switch back.

2, greenlet module and class

We first look inside the property greenlet this module

<pre class="prettyprint hljs ruby" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">>>> import greenlet

dir(greenlet)
['GREENLET_USE_GC', 'GREENLET_USE_TRACING', 'GreenletExit', '_C_API', 'doc', 'file', 'loader', 'name', 'package', 'spec', 'version', 'error', 'getcurrent', 'gettrace', 'greenlet', 'settrace']
</pre>

Among them, the more important is getcurrent (), class greenlet, abnormal class GreenletExit.

GetCurrent () Returns the current instance greenlet;

GreenletExit: it is a special exception, the exception is triggered when the time, if not treated, can not be thrown into its parent (coroutine will be mentioned later return value or exception handling)

Then we look at greenlet.greenlet this category:

<pre class="prettyprint hljs ruby" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">>>>dir(greenlet.greenlet)
['GreenletExit', 'bool', 'class', 'delattr', 'dict', 'dir', 'doc', 'eq', 'format', 'ge', 'getattribute', 'getstate', 'gt', 'hash', 'init', 'init_subclass', 'le', 'lt', 'ne', 'new', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'str', 'subclasshook', '_stack_saved', 'dead', 'error', 'getcurrent', 'gettrace', 'gr_frame', 'parent', 'run', 'settrace', 'switch', 'throw']
</pre>

The more important attributes:

run: When greenlet start time will be called to this callable, if we need to inherit greenlet.greenlet, need to override this method

switch: It has been introduced, the switching between greenlet

parent: read-write property, described later

dead: If greenlet end of execution, then the property is true

throw: After switching to the specified abnormal immediately ran greenlet

Most greenlet mentioned later in the article refer to greenlet.greenlet this class, please note the difference

For greenlet, the most common wording is x = gr.switch (y). What this means is switched to gr, passing parameters y. When coroutine from another ( not necessarily gr this time to switch back), the value paid x.

<pre class="prettyprint hljs python" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">import greenlet

def test1(x, y):
z = gr2.switch(x + y)
print("test1:%s" % z)

def test2(a):
print('test2:%s' % a)
gr1.switch(10)

gr1 = greenlet.greenlet(test1)
gr2 = greenlet.greenlet(test2)
print(gr1.switch("Hello", "World"))
</pre>

Operating results as follows:

<pre class="hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 0.75em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">test2:HelloWorld
test1:10
None
</pre>

The above example, line 10 is switched from the main greenlet to gr1, test1 row 3 is switched to the GS2, and then hangs gr1, gr2 when the line 7 from gr1 cut back, the value (10) to the return value of z.

3, greenlet life cycle

Where the beginning of the article mentioned in the first example of gr2 actually did not end properly, we can borrow greenlet.dead to see this property

Operating results as follows:

<pre class="prettyprint hljs python" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> 1 import greenlet
2
3
4 def test1():
5 gr2.switch(1)
6 print("test1: finished")
7
8
9 def test2(x):
10 print("test2:first %s" % x)
11 gr1.switch()
12 print("test2:back")
13
14 gr1 = greenlet.greenlet(test1)
15 gr2 = greenlet.greenlet(test2)
16 gr1.switch()
17 print("gr1 is dead? : %s, gr2 is dead? :%s" % (gr1.dead, gr2.dead))
18 gr2.switch()
19 print("gr1 is dead? : %s, gr2 is dead? :%s" % (gr1.dead, gr2.dead))
</pre>

Operating results as follows:

<pre class="prettyprint hljs vbscript" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">test2:first 1
test1: finished
gr1 is dead? : True, gr2 is dead? :False
test2:back
gr1 is dead? : True, gr2 is dead? :True
</pre>

Only when the HS function performs the corresponding process is completed, coroutine will Die , so the first time Check gr2 not Die, because line 12 is switched out no cut back. In the main switch and then to gr2 when the back of the execution logic, gr2 Die

4, greenlet Notes

Use greenlet need to look at three things:

First: greenlet after creation, must end, can not switch out will not come back, or likely to cause a memory leak

Second: python each thread has its own main greenlet its corresponding sub-greenlet, greenlet between the threads can not be switched to each other

Third: there is not a circular reference, this is the official document clearly stated

<pre class="prettyprint hljs python" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"> 1 from greenlet import greenlet, GreenletExit
2 huge = []
3 def show_leak():
4 def test1():
5 gr2.switch()
6
7 def test2():
8 huge.extend([x* x for x in range(100)])
9 gr1.switch()
10 print 'finish switch del huge'
11 del huge[:]
12
13 gr1 = greenlet(test1)
14 gr2 = greenlet(test2)
15 gr1.switch()
16 gr1 = gr2 = None
17 print 'length of huge is zero ? %s' % len(huge)
18
19 if name == 'main':
20 show_leak()
</pre>

Test2 function in line 11, we will be huge empty, then the first 16 rows gr1, cited gr2 count down to zero. However, operating results tell us, line 11 and did not execute, so if a coroutine is not the normal end is very dangerous, often do not meet expectations programmers. greenlet provides a solution to this problem, the official website documentation mentions: If greenlet a reference to the instance count becomes 0, then throws an exception in the last pending GreenletExit place, which makes we can try ... finally processing resource leaks. The following code:

<pre class="prettyprint hljs python" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">1 from greenlet import greenlet, GreenletExit
2 huge = []
3 def show_leak():
4 def test1():
5 gr2.switch()
6
7 def test2():
8 huge.extend([x* x for x in range(100)])
9 try:
10 gr1.switch()
11 finally:
12 print 'finish switch del huge'
13 del huge[:]
14
15 gr1 = greenlet(test1)
16 gr2 = greenlet(test2)
17 gr1.switch()
18 gr1 = gr2 = None
19 print 'length of huge is zero ? %s' % len(huge)
20
21 if name == 'main':
22 show_leak()
</pre>

Code above process switch: main greenlet -> gr1 -> gr2 -> gr1 -> main greenlet, gr2 obviously not normally ended (blowing in line 10). After line 18 gr1, gr2 have become the reference count of 0, it will throw an exception GreenletExit in line 10, so finally have the opportunity to execute the statement. Meanwhile, at the beginning of the article presentation Greenlet module, it also mentioned, GreenletExit this exception will not be thrown to the parent, so the main greenlet not the exception.

四, peddled

greenlet coroutine has been achieved, but also of the manual switching, is not that too much trouble, do not catch anxious, python has a more powerful than greenlet and module can automatically switch tasks gevent

The principle is that when a greenlet encounters IO (input output means is input and output, such as a network, file operation, etc.) operations, such as access to the network, it automatically switches to the other greenlet, IO operation until completed, then at the appropriate time switch back to continue.

Since the IO operation is very time-consuming, often make the program in a wait state, with gevent automatically switch coroutine for us to ensure that there is always greenlet running, instead of waiting for IO

<pre class="prettyprint hljs python" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">import gevent

def f():
for i in range(5):
print("%s:%d"%(gevent.getcurrent(),i))

g1 = gevent.spawn(f)
g2 = gevent.spawn(f)
g3 = gevent.spawn(f)
g1.join()
g2.join()
g3.join()
</pre>

Operating results as follows:

<pre class="prettyprint hljs go" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><Greenlet at 0x1ba533f9598: f(5)>:0
<Greenlet at 0x1ba533f9598: f(5)>:1
<Greenlet at 0x1ba533f9598: f(5)>:2
<Greenlet at 0x1ba533f9598: f(5)>:3
<Greenlet at 0x1ba533f9598: f(5)>:4
<Greenlet at 0x1ba533f97b8: f(5)>:0
<Greenlet at 0x1ba533f97b8: f(5)>:1
<Greenlet at 0x1ba533f97b8: f(5)>:2
<Greenlet at 0x1ba533f97b8: f(5)>:3
<Greenlet at 0x1ba533f97b8: f(5)>:4
<Greenlet at 0x1ba533f99d8: f(5)>:0
<Greenlet at 0x1ba533f99d8: f(5)>:1
<Greenlet at 0x1ba533f99d8: f(5)>:2
<Greenlet at 0x1ba533f99d8: f(5)>:3
<Greenlet at 0x1ba533f99d8: f(5)>:4
</pre>

We can see, three greenlet is followed by alternating running and not running

gevent switching execution

<pre class="prettyprint hljs python" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">import gevent

def f():
for i in range(5):
print("%s:%d"%(gevent.getcurrent(),i))
gevent.sleep(0)

g1=gevent.spawn(f)
g2=gevent.spawn(f)
g3=gevent.spawn(f)
g1.join()
g2.join()
g3.join()
</pre>

Implementation of the results:

<pre class="prettyprint hljs xml" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><Greenlet at 0x20a5e719598: f>:0
<Greenlet at 0x20a5e7197b8: f>:0
<Greenlet at 0x20a5e7199d8: f>:0
<Greenlet at 0x20a5e719598: f>:1
<Greenlet at 0x20a5e7197b8: f>:1
<Greenlet at 0x20a5e7199d8: f>:1
<Greenlet at 0x20a5e719598: f>:2
<Greenlet at 0x20a5e7197b8: f>:2
<Greenlet at 0x20a5e7199d8: f>:2
<Greenlet at 0x20a5e719598: f>:3
<Greenlet at 0x20a5e7197b8: f>:3
<Greenlet at 0x20a5e7199d8: f>:3
<Greenlet at 0x20a5e719598: f>:4
<Greenlet at 0x20a5e7197b8: f>:4
<Greenlet at 0x20a5e7199d8: f>:4
</pre>

3 run alternately greenlet

gevent.spawn start coroutine, as a function of the parameter name, parameter name

3, gevent concurrent Downloader

monkey can make some occluded module becomes unblocked, mechanisms: IO operations encountered is automatically switched, switching can be manual gevent.sleep (0)

<pre class="prettyprint hljs python" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">from gevent import monkey
import gevent
import urllib.request

There are I / need this one when O, if not this sentence will be blocked, plus there is no blocking

monkey.patch_all()

def myDownLoad(url):
print("GET:%s"%url)
resp = urllib.request.urlopen(url)
data = resp.read()
print("%d bytes received from %s"%(len(data),url))

gevent.joinall((
gevent.spawn(myDownLoad,"http://www.baidu.com/"),
gevent.spawn(myDownLoad,"https://apple.com"),
gevent.spawn(myDownLoad,"https://www.cnblogs.com/Se7eN-HOU/")
))
</pre>

Operating results as follows:

<pre class="prettyprint hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">GET:http://www.baidu.com/
GET:https://apple.com
GET:https://www.cnblogs.com/Se7eN-HOU/
153390 bytes received from http://www.baidu.com/
18880 bytes received from https://www.cnblogs.com/Se7eN-HOU/
58865 bytes received from https://apple.com
</pre>

Can be seen from the baidu is to obtain the relevant information is sent first, and then followed by apple, cnblogs but not necessarily the same order they are received and the data transmission order, which also reflects the asynchronous, that is uncertain when it will receive data, not necessarily sequentially.

If this code is not below the top,

<pre class="prettyprint hljs makefile" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">#有I/O时需要这一句,如果没有这句话就会有阻塞状态,加上就没有阻塞
monkey.patch_all()
</pre>

Execution results are as follows

<pre class="prettyprint hljs less" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">GET:http://www.baidu.com/
153378 bytes received from http://www.baidu.com/
GET:https://apple.com
58865 bytes received from https://apple.com
GET:https://www.cnblogs.com/Se7eN-HOU/
18880 bytes received from https://www.cnblogs.com/Se7eN-HOU/
</pre>

Each site will request a waiting request finished second in execution, in the course of the request, Suman wait state that is blocked.

Five, asyncio

We all know that the server development priority for control of the IO scheduling no longer rely on the system, and hope that the use of coroutines efficient way of concurrent tasks, such as js, lua, etc. in an asynchronous coroutine They have made very strong .

Python 3.4 version also added the concept of coroutines, and 3.5 establishes the basic syntax and perfect implementation. 3.6 was carried out at the same time also await and optimizing the yield is released as a function of the body in the same restrictions.

event_loop event loop: start a program infinite loop, the programmer will register some functions to the event loop. When satisfied incident, call the appropriate coroutine function.

coroutine coroutine: coroutine object refers to a function defined using async keyword, it will not execute the function call immediately, but will return a coroutine object. Coroutine objects need to be registered to the event loop, called by the event loop.

Task task: a coroutine object is a native function may be suspended, the task is further encapsulated to coroutine, various states of the tasks contained therein.

future: a guide to future results or perform tasks not performed. There is no essential difference between it and the task

async / await keywords: python3.5-defined keywords for coroutines, async definition of a coroutine, await for suspending blocking asynchronous call interface.

1, create a coroutine

First define a coroutine, DEF added async declared before, can define a coroutine function.

A coroutine function can not call directly run, only the coroutine added to the loop in the event loop. asyncio.get_event_loop method can create an event loop, and then use the coroutine run_until_complete registered to the event loop, and start the event loop.

E.g:

<pre class="prettyprint hljs python" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">import asyncio

DEF Fun the async ():
Print ( "coroutine --- ---")

main DEF ():
Print ( "main thread --- ---")

loop = asyncio.get_event_loop()
loop.run_until_complete(fun())

if name == "main":
main()
</pre>

operation result:

<pre class="hljs lua" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 0.75em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">---主线程中---
---协程中---
</pre>

Second, the task object task

Coroutine object can not be run directly, at the time of registration of the event loop, in fact run_until_complete method coroutine packaging has become a task (task) object. The so-called task object is a subclass Future class. Save the state of co-operation process for obtaining future results coroutine.

E.g:

<pre class="prettyprint hljs python" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">import asyncio

async def fun():
print("---协程中---")
return "Se7eN_HOU"

main DEF ():
Print ( "main thread --- ---")

loop = asyncio.get_event_loop()
#创建task
task = loop.create_task(fun())
print(task)
loop.run_until_complete(task)
print(task)

if name == "main":
main()
</pre>

Operating results as follows:

<pre class="prettyprint hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">---主线程中---
<Task pending coro=<fun() running at C:>> /Users/Se7eN_HOU/PycharmProjects/PythonLesson/test.py:4
--- --- Association process
<Task finished coro=<fun() done, defined at C:/Users/Se7eN_HOU/PycharmProjects/PythonLesson/test.py:4> result='Se7eN_HOU'>
</pre>

After creating the task, task before joining the event loop is pending in the state, because the fun () is not blocking time-consuming operation, task quickly finished up. finished state of print behind.

asyncio.ensure_future and loop.create_task can create a task, run_until_complete parameter is a futrue object.

Third, the binding callback

<pre class="prettyprint hljs python" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">import asyncio

Coroutine

async def fun():
print("---协程中---")
return "Se7eN_HOU"

Coroutine callback

the callback DEF (Future):
# future.result coroutine return value
print ( "callBack:% s" % future.result ())

main DEF ():
Print ( "main thread --- ---")
# Create a loop circuit
loop = asyncio.get_event_loop ()
# Create Task
Task = loop.create_task (Fun ())
# call the callback function
task.add_done_callback (callback)
Print (Task)
loop.run_until_complete (Task)
Print (Task)

if name == "main":
main()
</pre>

Operating results as follows:

<pre class="prettyprint hljs groovy" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">---主线程中---
<Task pending coro=<fun() running at C:/Users/Se7eN_HOU/PycharmProjects/PythonLesson/test.py:4> cb=[callback() at C:/Users/Se7eN_HOU/PycharmProjects/PythonLesson/test.py:9]>
---协程中---
callBack:Se7eN_HOU
<Task finished coro=<fun() done, defined at C:/Users/Se7eN_HOU/PycharmProjects/PythonLesson/test.py:4> result='Se7eN_HOU'>
</pre>

You can also use the return value of get ensure_future

E.g:

<pre class="prettyprint hljs python" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">import asyncio

Coroutine

async def fun():
print("---协程中---")
return "Se7eN_HOU"

Coroutine callback

def callback(future):

#future.result是协程的返回值
#print("callBack:%s"%future.result())

main DEF ():
# Create a loop circuit
loop = asyncio.get_event_loop ()
# Create a Task
#task = loop.create_task (Fun ())
# call the callback function
# task.add_done_callback (callback)
Task = asyncio.ensure_future (Fun () )
loop.run_until_complete (Task)
Print ( "the return value of the function is fun:% s"% format (task.result ()))

if name == "main":
main()
</pre>

Operating results as follows:

<pre class="hljs kotlin" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 0.75em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">---协程中---
fun函数的返回值是:Se7eN_HOU
</pre>

Four, await obstruction, concurrent execution

Use async coroutine objects can be defined using await can be suspended for a time-consuming operation, like the generator in the yield, the function allows a control. Coroutine encounters await, the event loop will suspend the co-drive the implementation of other coroutine until the other coroutine also suspend or finished, and then perform the next coroutine.

Typically some time-consuming operations IO operations, such as network requests, file reading and the like. We use asyncio.sleep function to simulate the IO operation. The purpose is to let these coroutines of asynchronous IO operations.

E.g:

<pre class="prettyprint hljs python" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 1.5em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">import asyncio

async def test1():
print("---1---")
await asyncio.sleep(5)
print("---2---")

async def test2():
print("---3---")
await asyncio.sleep(1)
print("---4---")

async def test3():
print("---5---")
await asyncio.sleep(3)
print("---6---")

def main():
loop = asyncio.get_event_loop()
print("begin")

t1 = test1()
t2 = test2()
t3 = test3()
tasks1 = [t1,t2,t3]

loop.run_until_complete(asyncio.wait(tasks1))
print("end")
loop.close()

if name=="main":
main()
</pre>

Operating results as follows:

<pre class="hljs sql" style="padding: 0.5em; font-family: Menlo, Monaco, Consolas, "Courier New", monospace; color: rgb(68, 68, 68); border-radius: 4px; display: block; margin: 0px 0px 0.75em; font-size: 14px; line-height: 1.5em; word-break: break-all; overflow-wrap: break-word; white-space: pre; background-color: rgb(246, 246, 246); border: none; overflow-x: auto; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">begin
---3---
---1---
---5---
---4---
---6---
---2---
end</pre>

Reproduced in: https: //www.jianshu.com/p/64078e87f984

Guess you like

Origin blog.csdn.net/weixin_34383618/article/details/91241194