Python 函數與常用模組 - 生成器並行運算

Posted 我不会

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 函數與常用模組 - 生成器並行運算相关的知识,希望对你有一定的参考价值。

目前我們已經大致上都了解生成器了,但要怎麼實際應用呢?!接下來就要舉個例子

yield 保存了這個函數的中斷狀態,返回當前這個狀態的值,並且把函數停在這,想什麼時候回來執行就什麼時候回來執行。

通過yield實現單綫程的情況下,實現並發運算的效果

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

def consumer(name):
    print("%s 準備吃包子啦!" %name)
    while True:
       baozi = yield  # baozi 沒有返回值就會為none

       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
       
 c = consumer("Tony")
 c.__next__()
      
       
---------------執行結果---------------
Tony 準備吃包子啦!

Process finished with exit code 0

生成一個消費者叫Tony,其實上面代碼就是一個生成器,所以要用 __next__() 這個方法去調用,但只有一個 __next__() 方法,程序會停在 baozi = yield 就結束了,那下面的就不會去執行了,那如果要繼續執行下面的話,要怎麼做呢?!

其實很簡單,在調用一次 __next__() 方法,就可以了

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

def consumer(name):
    print("%s 準備吃包子啦!" %name)
    while True:
       baozi = yield  # baozi 沒有返回值就會為none

       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))
       
 c = consumer("Tony")
 c.__next__()
 c.__next__()     
       
---------------執行結果---------------
Tony 準備吃包子啦!
包子[None]来了,被[Tony]吃了!

Process finished with exit code 0

耶!包子被打印出來了,注意,包子變成none,而這個none是代表包子為空,當然就沒有包子可以吃,那要怎麼做一個包子給Tony?

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

# import time
def consumer(name):
    print("%s 準備吃包子啦!" %(name))
    while True:
       baozi = yield

       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))

c = consumer("Tony")
c.__next__()

b1 = "韭菜餡"
c.send(b1)

---------------執行結果---------------
Tony 準備吃包子啦!
包子[韭菜餡]来了,被[Tony]吃了!

Process finished with exit code 0

我們製作一個包子叫 b1 = "韭菜餡" ,並且透過 send() 這個方法來給Tony包子吃。

  • send() 其實就是去調用yield,同時也給它傳一個值。
  • __next__() 就只是去調用yield,並不會傳值給yield。

看下面代碼就可以更清楚了解

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import time
def consumer(name):
    print("%s 準備吃包子啦!" %(name))
    while True:
       baozi = yield

       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))

c = consumer("Tony")
c.__next__()

b1 = "韭菜餡"
c.send(b1)
c.__next__()

---------------執行結果---------------
Tony 準備吃包子啦!
包子[韭菜餡]来了,被[Tony]吃了!
包子[None]来了,被[Tony]吃了!

Process finished with exit code 0

觀察一下,有發現第二個__next__() 的確沒有傳值,就只有去調用而已。

有沒有發現上面代碼裡面看起來很像二個任務在交互,所以接下來我們就把做包子的過程規範一點。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import time
def consumer(name):
    print("%s 準備吃包子啦!" %(name))
    while True:
       baozi = yield

       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))

def producer(name):
    c = consumer(‘A‘)
    c2 = consumer(‘B‘)
    c.__next__()
    c2.__next__()
    print("老子开始準備做包子啦!")
    for i in range(10):
        time.sleep(1)
        print("做了1個包子分兩半!")
        c.send(i)
        c2.send(i)

producer("tony")

---------------執行結果---------------
A 準備吃包子啦!
B 準備吃包子啦!
老子开始準備做包子啦!
做了1個包子分兩半!
包子[0]来了,被[A]吃了!
包子[0]来了,被[B]吃了!
做了1個包子分兩半!
包子[1]来了,被[A]吃了!
包子[1]来了,被[B]吃了!
做了1個包子分兩半!
包子[2]来了,被[A]吃了!
包子[2]来了,被[B]吃了!
做了1個包子分兩半!
包子[3]来了,被[A]吃了!
包子[3]来了,被[B]吃了!
做了1個包子分兩半!
包子[4]来了,被[A]吃了!
包子[4]来了,被[B]吃了!
做了1個包子分兩半!
包子[5]来了,被[A]吃了!
包子[5]来了,被[B]吃了!
做了1個包子分兩半!
包子[6]来了,被[A]吃了!
包子[6]来了,被[B]吃了!
做了1個包子分兩半!
包子[7]来了,被[A]吃了!
包子[7]来了,被[B]吃了!
做了1個包子分兩半!
包子[8]来了,被[A]吃了!
包子[8]来了,被[B]吃了!
做了1個包子分兩半!
包子[9]来了,被[A]吃了!
包子[9]来了,被[B]吃了!

Process finished with exit code 0

單綫程下的並行效果就出來,實際上還是串行的,因為可以在不同的角色中切換,並且因為運行速度特別快,所以感覺上像是並行的,這個就是『異步IO』的雛形。

epoll的底層原理跟上面這個代碼差不多,本質上是這樣做的。

我們管上面這種代碼,叫『協程』,可以理解成最簡單的協程,也是一個典型的基本的生產者消費模型,簡單說,就理解成一個人在生產,一個在消費。

以上是关于Python 函數與常用模組 - 生成器並行運算的主要内容,如果未能解决你的问题,请参考以下文章

Python 函數與常用模組 - 迭代器

SQL练习-SQLZOO SQLZOO:SUM and COUNT

SQL练习-SQLZOO SQLZOO:SUM and COUNT

C++ 基本知識回顧

我在一三年翻譯了一本書,書名是《HASKELL並行與並發編程》。

小數點的運算[討論區- PHP新手區] : 台灣PHP聯盟