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的底層原理跟上面這個代碼差不多,本質上是這樣做的。

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

时间: 2024-10-14 15:05:02

Python 函數與常用模組 - 生成器並行運算的相关文章

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

迭代器 我們已經知道可以直接作用於 for 循環的數據類型有以下幾種: 一類是集合數據類型: list . tuple . dict . set . str . bytes 等. 另一類是 generator ,包括生成器和帶 yield 的 generator function. 這些可以直接作用於 for 循環的對象,統稱為可迭代的對象( Iterable ): 可迭代的對象,可以把它想成就是 可以循環的對象, 可迭代 = 可循環 可以使用 isinstance() 判斷一個對象是否為 It

Python 函數 Function

函數最初被設計出來,是用來減輕重複 coding 一段相同的代碼,這之間只有代碼 (方法,Method) 的重用,但還沒有物件導向OO整個Object 的屬性與方法被封裝重用的概念. 函數的定義很簡單,使用 def 這保留字,而其宣告方式如下: def 函數名(參數名) : 例如: >>> def print_count(): # 函數宣告...    print('Good')...    print('Morning')...    print('Mr.')...>>&g

OpenERP函數字段的應用

在ERP開發過程中經常會使用到某字段的值是由其他字段計算得來,並且有些還需要將計算的結果存入資料庫. 以上功能上OpenERP中是用field.function實現的 其中有種模式 a). 只計算,不存儲 這種方式比較簡單,只需要設定用來計算值的函數即可,函數分類method和function,method是指當前對象的方法,function是指一般的python函數,有特定簽名的函數 [python] view plaincopy 'amount': fields.function(_amt,

DB2常用函數總結

最近用DB2,数据库之间的差异还是很大的,好多函数都不一样 1.去空格 *DB2中:Ltrim()是去左边空格,rtrim()是去右边空格.*informix中:trim()就是去空格.用法:例:string a="  abc  ";     *DB2中:Ltrim(a)="abc  ";rtrim(a)="  abc",rtrim(ltrim(a))="abc";     *informix中:trim(a)="a

[DE0-NANO] HC-05藍芽模組實現與測試(二)

篇是接續  [DE0-NANO] HC-05藍芽模組實現與測試(一) 本篇主要功能是將RFS板與電腦連接.硬體程式與上一篇相同. 在NIOS軟體部分,我新增了一個SLAVE模式,把RFS板上的HC05設為被動模式(SLAVE). 操作步驟 -------------------------------------------------------------------------- 1. 下載 DE0_Nano.sof 2.斷掉RFS板子電源,按下BT_KEY後在接上RFS板子電源. (此時

對比:莫比烏斯反演與歐拉函數

最近題讓我非常困惑,貌似我現在已經完全分不清楚哪些題用莫比烏斯反演,哪些用歐拉函數. 下面簡單總結一下,莫比烏斯反演處理的是 求segma(gcd(x,y)) 1<=x<=n,1<=y<=m (見<能量項鍊>) gcd(x,y) = k   1<=x<=n 1<=y<=m  求x,y對數 (見<bzoj 2301  problem b>) 莫比烏斯反演原來是解決以上問題2的,大體思路是 設F(a,b,k)表示1<=x<=a

非靜態初始化塊與夠着函數的 執行順序

題目: 子類A繼承父類B,A a=new A();則父類B夠着函數.父類B靜態代碼塊.父類B非靜態代碼塊執行的先後順序是? 正確的執行順序是:杜磊B靜態代碼塊->子類A靜態代碼塊->父類B非靜態代碼塊->父類B構造函數->子類A非靜態代碼塊->子類A構造函數 也就是説非靜態初始化塊的執行順序要在構造函數之前. 1 class SuperClass{ 2 private static String str="Spuer Class Static Variable&qu

學習日記:函數和對象

2016-2-21 1. Living without an aim is like sailing without a compass. 生活沒有目標,猶如航海沒有羅盤. 2. 無論是現實世界還是計算機世界,可讀性都是相當重要的,因為這涉及到人們的意識或者是認識效率,一般文字比數字的可理解性和可讀性要好,圖片的可讀性最強. a) 一般數學是比較抽象的,因為其中充滿著各種阿拉伯數字和已經不能再簡化的希臘字符. b) 數學家的得意之作就是覺得自己是在世界科學界的最巔峰. c) 我們能用數學工具處理

第六章:Python基础の反射与常用模块解密

本課主題 反射 Mapping 介绍和操作实战 模块介绍和操作实战 random 模块 time 和 datetime 模块 logging 模块 sys 模块 os 模块 hashlib 模块 re 模块 本周作业 反射 Mapping 介绍和操作实战 反射是利用字符串的形式去对象 (模块) 中操作 (寻找/检查) 成员 案例例子 假设创建了一个common.py 程序里而有3个功能,比如网站里的登录页面.主页页面还有登出页面都是不同的页面,要显示的内容都不一样. def login(): p