#coding:utf-8-*- '''協程(coroutine)又稱微線程、纖程,是一種用戶級的輕量級線程。協程有本身的寄存器上下文和棧。攜程調度時,將寄存器上下文和棧 保存,在切換回來的時候恢復保存的寄存器上下文和棧。因此每次重入時,就至關於進入上一次的調用狀態,在併發編程中協程與線程相似,每一個協 程標識一個執行單元有本身的本地數據與其餘協程共享全局數據和資源。 協程須要用戶自行編寫調度邏輯,對CPU來說協程是單線程的,因此CPU不用考慮怎麼調度、切換上下文節約CPU開銷,因此協程在必定程度上 又優於多線程。 python在默認提供了yield對協程進行基本的支持,但不徹底,建議使用第三方庫:gevent,其提供了比較完善的協程支持。 gevent對協程的支持,本質上來說是greenlet在實現切換工做,greenlet的工做流程以下: ---加入IO操做出現阻塞,greenlet就顯示的切換到另外一端沒有被阻塞的代碼段執行,指導原先的阻塞狀態消失,在切換回原來的代碼段 繼續執行。 gevent爲咱們自動切換協程就保證了總有greenlet在運行而不是等待IO操做,這就是協程比多線程效率高的緣由''' #gevent的使用 # from gevent import monkey # # from gevent import monkey.patch_all # import gevent # import urllib2 # from idlelib.rpc import response_queue # from greenlet import greenlet # def run_task(url): # print("Visit-->%s"%url) # try: # response=urllib2.urlopen(url) # date=response.read() # print('%d bytes received from %s' %(len(date),url)) # except Exception as e: # print(e) # if __name__=="__main__": # urls=['https://github.com/','https://www.python.org/','http://cnblogs.com/'] # greenlets=[gevent.spawn(run_task,url)for url in urls] # gevent.joinall(greenlets) #以上主要使用了gevent中的spawn方法和joinall方法, spawn用來造成協程,joinall方法用來添加這些任務並啓動 #以上三個網絡操做是併發執行的而結束順序不一樣,但實際只有一個線程 #------------------------------------------------------------------------------------- #使用gevent的pool對象進行動態數量的greenlent併發管理 from gevent import monkey monkey.patch_all() import urllib2 from gevent.pool import Pool def run_task(url): print('Visit-->%s'%url) try: response=urllib2.urlopen(url) data=response.read() print('%d bytes reveived from %s.' %(len(data),url)) except Exception as e: print(e) return 'url:%s-->finish'%url if __name__=="__main__": pool=Pool(2) urls=['https://github.com/','https://www.python.org/','http://www.cnblogs.com/'] results=pool.map(run_task,urls) print(results) #以上程序中Pool對象對協程的併發數量進行了管理,先訪問了前兩個網址,當其中一個任務完成時纔會訪問第三個