欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

Python協(xié)程概念及其用法是什么

這篇文章將為大家詳細(xì)講解有關(guān)Python協(xié)程概念及其用法是什么,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

讓客戶(hù)滿(mǎn)意是我們工作的目標(biāo),不斷超越客戶(hù)的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶(hù),將通過(guò)不懈努力成為客戶(hù)在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:域名注冊(cè)、虛擬主機(jī)、營(yíng)銷(xiāo)軟件、網(wǎng)站建設(shè)、長(zhǎng)沙網(wǎng)站維護(hù)、網(wǎng)站推廣。

對(duì)于協(xié)程,我表示其效率確非多線(xiàn)程能比,但本人對(duì)此了解并不深入,因此最近幾日參考了一些資料,學(xué)習(xí)整理了一番,在此分享出來(lái)僅供大家參考

協(xié)程

概念

協(xié)程,又稱(chēng)微線(xiàn)程,纖程,英文名Coroutine。協(xié)程的作用,是在執(zhí)行函數(shù)A時(shí),可以隨時(shí)中斷,去執(zhí)行函數(shù)B,然后中斷繼續(xù)執(zhí)行函數(shù)A(可以自由切換)。但這一過(guò)程并不是函數(shù)調(diào)用(沒(méi)有調(diào)用語(yǔ)句),這一整個(gè)過(guò)程看似像多線(xiàn)程,然而協(xié)程只有一個(gè)線(xiàn)程執(zhí)行。

優(yōu)勢(shì)

  • 執(zhí)行效率極高,因?yàn)樽映绦蚯袚Q(函數(shù))不是線(xiàn)程切換,由程序自身控制,沒(méi)有切換線(xiàn)程的開(kāi)銷(xiāo)。所以與多線(xiàn)程相比,線(xiàn)程的數(shù)量越多,協(xié)程性能的優(yōu)勢(shì)越明顯。

  • 不需要多線(xiàn)程的鎖機(jī)制,因?yàn)橹挥幸粋€(gè)線(xiàn)程,也不存在同時(shí)寫(xiě)變量沖突,在控制共享資源時(shí)也不需要加鎖,因此執(zhí)行效率高很多。

說(shuō)明:協(xié)程可以處理IO密集型程序的效率問(wèn)題,但是處理CPU密集型不是它的長(zhǎng)處,如要充分發(fā)揮CPU利用率可以結(jié)合多進(jìn)程+協(xié)程。

以上只是協(xié)程的一些概念,可能聽(tīng)起來(lái)比較抽象,那么我結(jié)合代碼講一講吧。這里主要介紹協(xié)程在Python的應(yīng)用,Python2對(duì)協(xié)程的支持比較有限,生成器的yield實(shí)現(xiàn)了一部分但不完全,gevent模塊倒是有比較好的實(shí)現(xiàn);Python3.4以后引入了asyncio模塊,可以很好的使用協(xié)程。

Python2.x協(xié)程

python2.x協(xié)程應(yīng)用:

  • yield

  • gevent

python2.x中支持協(xié)程的模塊不多,gevent算是比較常用的,這里就簡(jiǎn)單介紹一下gevent的用法。

Gevent

gevent是第三方庫(kù),通過(guò)greenlet實(shí)現(xiàn)協(xié)程,其基本思想:

當(dāng)一個(gè)greenlet遇到IO操作時(shí),比如訪問(wèn)網(wǎng)絡(luò),就自動(dòng)切換到其他的greenlet,等到IO操作完成,再在適當(dāng)?shù)臅r(shí)候切換回來(lái)繼續(xù)執(zhí)行。由于IO操作非常耗時(shí),經(jīng)常使程序處于等待狀態(tài),有了gevent為我們自動(dòng)切換協(xié)程,就保證總有g(shù)reenlet在運(yùn)行,而不是等待IO。

Install

pip install gevent

***版貌似支持windows了,之前測(cè)試好像windows上運(yùn)行不了……

Usage

首先來(lái)看一個(gè)簡(jiǎn)單的爬蟲(chóng)例子:

#! -*- coding:utf-8 -*-  import gevent  from gevent import monkey;monkey.patch_all()  import urllib2  def get_body(i):  print "start",i  urllib2.urlopen("http://cn.bing.com")  print "end",i  tasks=[gevent.spawn(get_body,i) for i in range(3)]  gevent.joinall(tasks)

運(yùn)行結(jié)果:

start 0  start 1  start 2  end 2  end 0  end 1

說(shuō)明:從結(jié)果上來(lái)看,執(zhí)行g(shù)et_body的順序應(yīng)該先是輸出”start”,然后執(zhí)行到urllib2時(shí)碰到IO堵塞,則會(huì)自動(dòng)切換運(yùn)行下一個(gè)程序(繼續(xù)執(zhí)行g(shù)et_body輸出start),直到urllib2返回結(jié)果,再執(zhí)行end。也就是說(shuō),程序沒(méi)有等待urllib2請(qǐng)求網(wǎng)站返回結(jié)果,而是直接先跳過(guò)了,等待執(zhí)行完畢再回來(lái)獲取返回值。值得一提的是,在此過(guò)程中,只有一個(gè)線(xiàn)程在執(zhí)行,因此這與多線(xiàn)程的概念是不一樣的。

換成多線(xiàn)程的代碼看看:

import threading  import urllib2  def get_body(i):  print "start",i  urllib2.urlopen("http://cn.bing.com")  print "end",i  for i in range(3):  t=threading.Thread(target=get_body,args=(i,))  t.start()

運(yùn)行結(jié)果:

start 0  start 1  start 2  end 1  end 2  end 0

說(shuō)明:從結(jié)果來(lái)看,多線(xiàn)程與協(xié)程的效果一樣,都是達(dá)到了IO阻塞時(shí)切換的功能。不同的是,多線(xiàn)程切換的是線(xiàn)程(線(xiàn)程間切換),協(xié)程切換的是上下文(可以理解為執(zhí)行的函數(shù))。而切換線(xiàn)程的開(kāi)銷(xiāo)明顯是要大于切換上下文的開(kāi)銷(xiāo),因此當(dāng)線(xiàn)程越多,協(xié)程的效率就越比多線(xiàn)程的高。(猜想多進(jìn)程的切換開(kāi)銷(xiāo)應(yīng)該是***的)

Gevent使用說(shuō)明

  • monkey可以使一些阻塞的模塊變得不阻塞,機(jī)制:遇到IO操作則自動(dòng)切換,手動(dòng)切換可以用gevent.sleep(0)(將爬蟲(chóng)代碼換成這個(gè),效果一樣可以達(dá)到切換上下文)

  • gevent.spawn 啟動(dòng)協(xié)程,參數(shù)為函數(shù)名稱(chēng),參數(shù)名稱(chēng)

  • gevent.joinall 停止協(xié)程

Python3.x協(xié)程

為了測(cè)試Python3.x下的協(xié)程應(yīng)用,我在virtualenv下安裝了python3.6的環(huán)境。

python3.x協(xié)程應(yīng)用:

  • asynico + yield from(python3.4)

  • asynico + await(python3.5)

  • gevent

Python3.4以后引入了asyncio模塊,可以很好的支持協(xié)程。

asynico

asyncio是Python 3.4版本引入的標(biāo)準(zhǔn)庫(kù),直接內(nèi)置了對(duì)異步IO的支持。asyncio的異步操作,需要在coroutine中通過(guò)yield  from完成。

Usage

例子:(需在python3.4以后版本使用)

import asyncio  @asyncio.coroutine  def test(i):  print("test_1",i)  r=yield from asyncio.sleep(1)  print("test_2",i)  loop=asyncio.get_event_loop()  tasks=[test(i) for i in range(5)]  loop.run_until_complete(asyncio.wait(tasks))  loop.close()

運(yùn)行結(jié)果:

test_1 3  test_1 4  test_1 0  test_1 1  test_1 2  test_2 3  test_2 0  test_2 2  test_2 4  test_2 1

說(shuō)明:從運(yùn)行結(jié)果可以看到,跟gevent達(dá)到的效果一樣,也是在遇到IO操作時(shí)進(jìn)行切換(所以先輸出test_1,等test_1輸出完再輸出test_2)。但此處我有一點(diǎn)不明,test_1的輸出為什么不是按照順序執(zhí)行的呢?可以對(duì)比gevent的輸出結(jié)果(希望大神能解答一下)。

asyncio說(shuō)明

@asyncio.coroutine把一個(gè)generator標(biāo)記為coroutine類(lèi)型,然后,我們就把這個(gè)coroutine扔到EventLoop中執(zhí)行。

test()會(huì)首先打印出test_1,然后,yield  from語(yǔ)法可以讓我們方便地調(diào)用另一個(gè)generator。由于asyncio.sleep()也是一個(gè)coroutine,所以線(xiàn)程不會(huì)等待asyncio.sleep(),而是直接中斷并執(zhí)行下一個(gè)消息循環(huán)。當(dāng)asyncio.sleep()返回時(shí),線(xiàn)程就可以從yield  from拿到返回值(此處是None),然后接著執(zhí)行下一行語(yǔ)句。

把a(bǔ)syncio.sleep(1)看成是一個(gè)耗時(shí)1秒的IO操作,在此期間,主線(xiàn)程并未等待,而是去執(zhí)行EventLoop中其他可以執(zhí)行的coroutine了,因此可以實(shí)現(xiàn)并發(fā)執(zhí)行。

asynico/await

為了簡(jiǎn)化并更好地標(biāo)識(shí)異步IO,從Python 3.5開(kāi)始引入了新的語(yǔ)法async和await,可以讓coroutine的代碼更簡(jiǎn)潔易讀。

請(qǐng)注意,async和await是針對(duì)coroutine的新語(yǔ)法,要使用新的語(yǔ)法,只需要做兩步簡(jiǎn)單的替換:

把@asyncio.coroutine替換為async;

把yield from替換為await。

Usage

例子(python3.5以后版本使用):

import asyncio  async def test(i):  print("test_1",i)  await asyncio.sleep(1)  print("test_2",i)  loop=asyncio.get_event_loop()  tasks=[test(i) for i in range(5)]  loop.run_until_complete(asyncio.wait(tasks))  loop.close()

運(yùn)行結(jié)果與之前一致。

說(shuō)明:與前一節(jié)相比,這里只是把yield from換成了await,@asyncio.coroutine換成了async,其余不變。

gevent

同python2.x用法一樣。

協(xié)程VS多線(xiàn)程

如果通過(guò)以上介紹,你已經(jīng)明白多線(xiàn)程與協(xié)程的不同之處,那么我想測(cè)試也就沒(méi)有必要了。因?yàn)楫?dāng)線(xiàn)程越來(lái)越多時(shí),多線(xiàn)程主要的開(kāi)銷(xiāo)花費(fèi)在線(xiàn)程切換上,而協(xié)程是在一個(gè)線(xiàn)程內(nèi)切換的,因此開(kāi)銷(xiāo)小很多,這也許就是兩者性能的根本差異之處吧。(個(gè)人觀點(diǎn))

異步爬蟲(chóng)

也許關(guān)心協(xié)程的朋友,大部分是用其寫(xiě)爬蟲(chóng)(因?yàn)閰f(xié)程能很好的解決IO阻塞問(wèn)題),然而我發(fā)現(xiàn)常用的urllib、requests無(wú)法與asyncio結(jié)合使用,可能是因?yàn)榕老x(chóng)模塊本身是同步的(也可能是我沒(méi)找到用法)。那么對(duì)于異步爬蟲(chóng)的需求,又該怎么使用協(xié)程呢?或者說(shuō)怎么編寫(xiě)異步爬蟲(chóng)?

給出幾個(gè)我所了解的方案:

  • grequests (requests模塊的異步化)

  • 爬蟲(chóng)模塊+gevent(比較推薦這個(gè))

  • aiohttp (這個(gè)貌似資料不多,目前我也不太會(huì)用)

  • asyncio內(nèi)置爬蟲(chóng)功能 (這個(gè)也比較難用)

協(xié)程池

作用:控制協(xié)程數(shù)量

from bs4 import BeautifulSoup  import requests  import gevent  from gevent import monkey, pool  monkey.patch_all()  jobs = []  links = []  p = pool.Pool(10)  urls = [      'http://www.google.com',      # ... another 100 urls  ]  def get_links(url):      r = requests.get(url)      if r.status_code == 200:          soup = BeautifulSoup(r.text)          links + soup.find_all('a')  for url in urls:      jobs.append(p.spawn(get_links, url))  gevent.joinall(jobs)

關(guān)于Python協(xié)程概念及其用法是什么就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

文章標(biāo)題:Python協(xié)程概念及其用法是什么
轉(zhuǎn)載來(lái)源:http://chinadenli.net/article22/ppgicc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開(kāi)發(fā)、用戶(hù)體驗(yàn)、ChatGPT、Google、動(dòng)態(tài)網(wǎng)站、網(wǎng)站內(nèi)鏈

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化