當前位置:首頁 » 編程語言 » pythonyield非同步

pythonyield非同步

發布時間: 2022-08-20 12:52:49

① 如何利用python asyncio編寫非同步爬蟲

  1. 你要安裝 python3.4 ,asyncio是Python 3.4版本引入的標准庫,直接內置了對非同步IO的支持。

例子

https://github.com/michaelliao/learn-python3/blob/master/samples/async/async_hello.py

  1. importasyncio

    @asyncio.coroutine
    defhello():
    print("Helloworld!")
    #非同步調用asyncio.sleep(1):
    r=yieldfromasyncio.sleep(1)
    print("Helloagain!")

    #獲取EventLoop:
    loop=asyncio.get_event_loop()
    #執行coroutine
    loop.run_until_complete(hello())
    loop.close()

### 這里非同步爬蟲 裡面不要用太多阻塞的類 如:python-mysqldb

async 學習資料:

  1. https://github.com/python/asyncio/wiki

  2. https://docs.python.org/3.4/library/asyncio.html

  3. http://asyncio.org/

② python yield怎麼實現的

yield是生成器關鍵詞,是在函數內使用的生成器語法(你也可以理解為是用在函數內的創建生成器的方法),讓函數返回的是一個生成器而不再返回函數計算得到的結果。比如:

同樣的迭代完再迭代則會報錯

③ python的關鍵字yield有什麼作用

yield是python中定義為生成器函數,其本質是封裝了 __iter__和__next__方法 的迭代器;



與return返回的區別:return只能返回一次值,函數就終止了,而yield能多次返回值,每次返回都會將函數暫停,下一次next會從上一次暫停的位置繼續執行;



以下用示例說明:



deftest(a,b):
print("fromtest(),a+b=%d"%(a+b))
return("我是return返回的")

deftest_yield(a,b): #函數體中有yield關鍵字,函數就可以稱為生成器函數
print("fromtest_yield,a+b=%d"%(a+b))
yield("我是第一次碰到yield關鍵字返回的") #程序運行時碰到yield,退出函數體並記錄位置,下次調用跳過之前運行的代碼
print("fromtest_yield,a*2=%d"%(a*2))
yield("我是第二次調用碰到yield關鍵字返回的")

print(test(11,33))
g=test_yield(11,33)
print(next(g)) #通過next()調用生成器函數
print(next(g)) #第二次調用生成器函數


'''
執行結果:

fromtest(),a+b=44
我是return返回的
fromtest_yield,a+b=44
我是第一次碰到yield關鍵字返回的
fromtest_yield,a*2=22
我是第二次調用碰到yield關鍵字返回的

'''

④ Python yield 語句

我在2x版本下測試下顯式調用throw來拋出GeneratorExit異常是可以被捕獲的

我查了一下文檔,樓主你的理解可能錯了,文檔的意思是說迭代器調用close退出時如果處於暫停狀態就會內部產生一個GeneratorExit異常,這個異常是不能捕獲的,內部會轉換成RuntimeError拋出

正常退出的話則產生StopIteration異常

測試代碼如下

defmy_generator():
try:
yield'dosomething'
exceptValueError:
yield'dealingwiththeexceptions'
exceptGeneratorExit:
yield"Yes,Icanyieldavalue"
finally:
print"Ok,let'sclean"

gen=my_generator()
gen.next()#這行注釋掉後則不會拋出異常
try:
gen.close()
exceptRuntimeError:
print"closeerror"

⑤ 如何看待 Python 3.5支持Async/Await非同步編程

根據Python增強提案(PEP) 第0492號, Python 3.5將通過async和await語法增加對協程的支持。該提案目的是使協程成為Python語言的原生特性,並「建立一種普遍、易用的非同步編程思維模型。」

這個新提議中聲明一個協程的語法如下:

async def read_data(db):
pass

async是明確將函數聲明為協程的關鍵字,即便沒有使用await表達式。這樣的函數執行時會返回一個協程對象。

在協程函數內部,可在某個表達式之前使用await關鍵字來暫停協程的執行,以等待某進程完成:

async def read_data(db):
data = await db.fetch('SELECT ...')
...

由於增強版生成器的存在,Python中其實早已有了協程的形式,例如當yield或yield from聲明在Python生成器內部出現,該生成器就會被當作協程。

以下示例展示基於生成器的協程的用法:

>>> def createGenerator():
... mylist = range(3)
... for i in mylist:
... yield i*i
...
>>> mygenerator = createGenerator()
>>> for i in mygenerator:
... print(i)
0
1
4

以上代碼中,每當生成器在for循環中被調用,該生成器中的for循環就會返回一個新的值。

關於await用法的更多示例請參見上文提到的PEP #0492.

這個關於協程的新提案想明確地把生成器與協程區分開,這么做有如下好處:

  • 使這兩個概念對新開發者來說更易於理解,因為它們二者的語法並不一樣;

  • 能消除由於重構時不小心移除了協程中的yield聲明而導致的「不明確錯誤」,這會導致協程變成普通的生成器。

  • async/await語法能讓程序員以序列方式編寫代碼,但編譯器則會將其當作一系列的協程來處理,從而實現有效的並發。回到我們之前的例子,async/await使我們可以順序地編寫多個await聲明語句,就好像每個語句都會阻塞並等待結果,但實際上這並不會導致任何阻塞:

  • async def read_data(db):

  • data = await db.fetch('SELECT ...')

  • if (data...)

  • await api.send(data ...')

⑥ python非同步有哪些方式

yield相當於return,他將相應的值返回給調用next()或者send()的調用者,從而交出了CPU使用權,而當調用者再次調用next()或者send()的時候,又會返回到yield中斷的地方,如果send有參數,還會將參數返回給yield賦值的變數,如果沒有就和next()一樣賦值為None。但是這里會遇到一個問題,就是嵌套使用generator時外層的generator需要寫大量代碼,看如下示例:
注意以下代碼均在Python3.6上運行調試

#!/usr/bin/env python# encoding:utf-8def inner_generator():
i = 0
while True:
i = yield i if i > 10: raise StopIterationdef outer_generator():
print("do something before yield")
from_inner = 0
from_outer = 1
g = inner_generator()
g.send(None) while 1: try:
from_inner = g.send(from_outer)
from_outer = yield from_inner except StopIteration: breakdef main():
g = outer_generator()
g.send(None)
i = 0
while 1: try:
i = g.send(i + 1)
print(i) except StopIteration: breakif __name__ == '__main__':
main()041

為了簡化,在Python3.3中引入了yield from

yield from

使用yield from有兩個好處,

1、可以將main中send的參數一直返回給最里層的generator,
2、同時我們也不需要再使用while循環和send (), next()來進行迭代。

我們可以將上邊的代碼修改如下:

def inner_generator():
i = 0
while True:
i = yield i if i > 10: raise StopIterationdef outer_generator():
print("do something before coroutine start") yield from inner_generator()def main():
g = outer_generator()
g.send(None)
i = 0
while 1: try:
i = g.send(i + 1)
print(i) except StopIteration: breakif __name__ == '__main__':
main()

執行結果如下:

do something before coroutine start123456789101234567891011

這里inner_generator()中執行的代碼片段我們實際就可以認為是協程,所以總的來說邏輯圖如下:

我們都知道Python由於GIL(Global Interpreter Lock)原因,其線程效率並不高,並且在*nix系統中,創建線程的開銷並不比進程小,因此在並發操作時,多線程的效率還是受到了很大制約的。所以後來人們發現通過yield來中斷代碼片段的執行,同時交出了cpu的使用權,於是協程的概念產生了。在Python3.4正式引入了協程的概念,代碼示例如下:

import asyncio# Borrowed from http://curio.readthedocs.org/en/latest/[email protected] countdown(number, n):
while n > 0:
print('T-minus', n, '({})'.format(number)) yield from asyncio.sleep(1)
n -= 1loop = asyncio.get_event_loop()
tasks = [
asyncio.ensure_future(countdown("A", 2)),
asyncio.ensure_future(countdown("B", 3))]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()12345678910111213141516

示例顯示了在Python3.4引入兩個重要概念協程和事件循環,
通過修飾符@asyncio.coroutine定義了一個協程,而通過event loop來執行tasks中所有的協程任務。之後在Python3.5引入了新的async & await語法,從而有了原生協程的概念。

async & await

在Python3.5中,引入了aync&await 語法結構,通過」aync def」可以定義一個協程代碼片段,作用類似於Python3.4中的@asyncio.coroutine修飾符,而await則相當於」yield from」。

先來看一段代碼,這個是我剛開始使用async&await語法時,寫的一段小程序。

#!/usr/bin/env python# encoding:utf-8import asyncioimport requestsimport time


async def wait_download(url):
response = await requets.get(url)
print("get {} response complete.".format(url))


async def main():
start = time.time()
await asyncio.wait([
wait_download("http://www.163.com"),
wait_download("http://www.mi.com"),
wait_download("http://www.google.com")])
end = time.time()
print("Complete in {} seconds".format(end - start))


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

這里會收到這樣的報錯:

Task exception was never retrieved
future: <Task finished coro=<wait_download() done, defined at asynctest.py:9> exception=TypeError("object Response can't be used in 'await' expression",)>
Traceback (most recent call last):
File "asynctest.py", line 10, in wait_download
data = await requests.get(url)
TypeError: object Response can't be used in 'await' expression123456

這是由於requests.get()函數返回的Response對象不能用於await表達式,可是如果不能用於await,還怎麼樣來實現非同步呢?
原來Python的await表達式是類似於」yield from」的東西,但是await會去做參數檢查,它要求await表達式中的對象必須是awaitable的,那啥是awaitable呢? awaitable對象必須滿足如下條件中其中之一:

1、A native coroutine object returned from a native coroutine function .

原生協程對象

2、A generator-based coroutine object returned from a function decorated with types.coroutine() .

types.coroutine()修飾的基於生成器的協程對象,注意不是Python3.4中asyncio.coroutine

3、An object with an await method returning an iterator.

實現了await method,並在其中返回了iterator的對象

根據這些條件定義,我們可以修改代碼如下:

#!/usr/bin/env python# encoding:utf-8import asyncioimport requestsimport time


async def download(url): # 通過async def定義的函數是原生的協程對象
response = requests.get(url)
print(response.text)


async def wait_download(url):
await download(url) # 這里download(url)就是一個原生的協程對象
print("get {} data complete.".format(url))


async def main():
start = time.time()
await asyncio.wait([
wait_download("http://www.163.com"),
wait_download("http://www.mi.com"),
wait_download("http://www.google.com")])
end = time.time()
print("Complete in {} seconds".format(end - start))


loop = asyncio.get_event_loop()
loop.run_until_complete(main())27282930

好了現在一個真正的實現了非同步編程的小程序終於誕生了。
而目前更牛逼的非同步是使用uvloop或者pyuv,這兩個最新的Python庫都是libuv實現的,可以提供更加高效的event loop。

uvloop和pyuv

pyuv實現了Python2.x和3.x,但是該項目在github上已經許久沒有更新了,不知道是否還有人在維護。
uvloop只實現了3.x, 但是該項目在github上始終活躍。

它們的使用也非常簡單,以uvloop為例,只需要添加以下代碼就可以了

import asyncioimport uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())123

⑦ python中yield的用法問題

yield就是保存當前程序執行狀態。
你用for循環的時候,每次取一個元素的時候就會計算一次。
用yield的函數叫generator,和iterator一樣,它的好處是不用一次計算所有元素,而是用一次算一次,可以節省很多空間。generator每次計算需要上一次計算結果,所以用yield,否則一return,上次計算結果就沒了。
所以保存列表的說法是完全錯誤的。

⑧ Python的yield問題

python yield from

defgenerator2():
foriinrange(10):
yieldidefgenerator3():
forjinrange(10,20):
yieldjdefgenerator():
foriingenerator2():
yieldi
forjingenerator3():
yieldj

==

defgenerator():
yieldfromgenerator2()
yieldfromgenerator3()

⑨ 關於python中yield函數

next()一次執行一次,並不一次性執行完,是個itertator.也可以通過for來執行

⑩ python中yield是什麼意思

一個帶有 yield 的函數就是一個 generator,它和普通函數不同,生成一個 generator 看起來像函數調用,但不會執行任何函數代碼,直到對其調用 next()(在 for 循環中會自動調用 next())才開始執行。雖然執行流程仍按函數的流程執行,但每執行到一個 yield 語句就會中斷,並返回一個迭代值,下次執行時從 yield 的下一個語句繼續執行。看起來就好像一個函數在正常執行的過程中被 yield 中斷了數次,每次中斷都會通過 yield 返回當前的迭代值。

具體,請參考下以下資料:
http://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/

熱點內容
2012文件伺服器如何新建用戶 發布:2025-01-19 02:43:10 瀏覽:884
android復試 發布:2025-01-19 02:39:11 瀏覽:654
c獲取文件夾中 發布:2025-01-19 02:33:48 瀏覽:547
如何查看360瀏覽器保存的密碼 發布:2025-01-19 02:27:14 瀏覽:94
源碼分享站 發布:2025-01-19 01:21:26 瀏覽:911
安卓如何設置方向鎖定生效 發布:2025-01-19 01:21:25 瀏覽:72
iis上傳限制 發布:2025-01-19 01:14:52 瀏覽:16
我的世界寶可夢伺服器181 發布:2025-01-19 01:12:32 瀏覽:183
如何用雲伺服器掛游戲 發布:2025-01-19 01:09:19 瀏覽:211
電腦系統還原如何清除緩存 發布:2025-01-19 01:08:08 瀏覽:782