Python並發實踐_02_協程

來源:互聯網
上載者:User

標籤:

python中實現並發的方式有很多種,通過多進程並發可以真正利用多核資源,而多線程並發則實現了進程內資源的共用,然而Python中由於GIL的存在,多線程是沒有辦法真正實現多核資源的。

對於計算密集型程式,應該使用多進程並發充分利用多核資源,而在IO密集型程式中,多核優勢並不明顯,甚至由於大多數時間都是在IO堵塞狀態,多進程的切換消耗反而讓程式效率更加低下。

而當需要並發處理IO密集型任務時,就需要用到協程(Coroutine)。協程並沒有系統級的調度,而是使用者級的調度方式,避免了系統調用的開銷,雖然協程最終是串列工作,但是卻可以實現非常大的並發量。

參考文章:

https://blog.tonyseek.com/post/event-manage-with-greenlet/

producer-consumer

利用yield產生器,可以簡單展現協程的工作方式:

import time
def consumer():
    print "Ready to receive"
    while True:
        y = (yield )
        time.sleep(1)
        print "Receive %s from producer”%y
def producer():
    c = consumer()
    c.next()
    i = 1
    while i > 0 and i < 11:
        time.sleep(1)
        print "Send %s to consumer"%i
        c.send(i)
        i += 1
if __name__ == ‘__main__‘:
    producer()

上述過程展示了基本的生產者-消費者模型,消費者consumer是一個產生器;

當第一次在producer中調用c.next()時,啟用consumer,並且運行到yield時協程(consumer)被掛起,等待產生器被調用next或者send。

producer進行後續操作,並進入一個迴圈,每次暫停1s後,向產生器send一個訊息,消費者yield擷取到該訊息,並進行後續的工作。

可以看到,每次yield都需要等待send傳入的訊息之後才會繼續執行之後的任務。

通過yield實現協程

現在要來用yield真正建立一個協程了。

可以想象這樣一個模型,一個工地裡有很多相似的任務(jobs),並且會源源不斷產生這些任務,工地裡有一個工頭(foreman)負責,工頭為了分配任務給工人(worker),會制定一套流程(pipeline)來方便管理:分配工人,驗收工作(accept),由於工人工作(work)的時間遠遠大於分配任務的時間,將這些工人的工作(簡單枯燥的重複勞動)看成IO操作的話,這就是一個IO密集型的任務。下面看看python是如何通過yield來實現協程完成真箇工作的:

 

 1 def main(): 2     foreman(args_of_overall,worker_num) 3  4 def foreman(args_of_overall,worker_num): 5     pipeline = create_pipeline(args_of_pipeline,worker_num) 6     for i,job in enumerate(get_jobs(args_of_ceate_jobs)): 7         worker_id  = i % worker_num 8         pipeline.send((job,worker_id)) 9 10 @coroutine11 def worker(pipeline,accepting,job,my_id):12     while True:13         args_of_job, worker_id = (yield )14         if worker_id == my_id:15             result = work(args_of_job)16             accepting.send(result)17         elif pipeline is not None:18             pipeline.send((job,worker_id))19 20 @coroutine21 def accept():22     while True:23         result = (yield )24         #do_some_accepting25 26 def create_pipeline(args_of_pipeline,worker_num):27     pipeline = None28     accepting = accept()29     for work_id in range(work_num):30         pipeline = worker(pipeline,accepting,job,work_id)31     return pipeline32 33 def get_jobs(args_of_ceate_jobs):34     for job in job_source:35         yield job36 37 def coroutine(func):38     def warper(*args):39         f = func(*args)40         f.next()41         return f42     return warper43 44 def work(args_of_job):45     pass46     #do_some_work47 48 if __name__ == ‘__main__‘:49     main()

 上述過程中,工人和驗收工作都是協程,而get_jobs()函數是一個產生器,當job是動態添加時,就可以改寫成一個協程,由此可見,產生器應該是一個特殊的協程。

上述所有的工作都是串列完成,雖然有很多工人,工人之間的工作是並發的(IO等待時間),但是工作一直是從第一個開始一個一個分配任務。

Python並發實踐_02_協程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.