Python--協程(gevent模塊)

一:前言

協程又稱為微線程,纖程。英文名Coroutine:協程是一種用戶態的輕量級線程

協程擁有自己的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢復之前保存的寄存器上下文和棧。因此:

協程能夠保留上次一調用時的狀態,能夠進入上一次離開時所處的邏輯流的位置

協程的好處

無需線程上下文切換的開銷
無需原子操作(不會被線程調度機制打斷的操作)鎖定以及同步的開銷
方便切換控制流,簡化編程模型
高并發+高擴展性+低成文:一個CPU支持上完的協程都不是問題,所以很適合高并發處理

協程的缺點

無法利用多核資源:協程的本質是單線程,需要和進程配合才能運行在多CPU上
進行阻塞(Blocking)操作(如IO時)會阻塞掉整個程序

協程的條件

必須在只有一個單線程里實現并發
修改共享數據不需加鎖
用戶程序里自己保存多個控制流的上下文棧
一個協程遇到IO操作自動切換到其它協程

使用yield實現協程

def consumer(name):print("--->starting eating baozi...")while True:new_baozi = yieldprint("[%s] is eating baozi %s" % (name, new_baozi))def producer():next(con)next(con2)n = 0while n < 5:n += 1con.send(n)con2.send(n)print("\033[32;1m[producer]\033[0m is making baozi %s" % n)if __name__ == '__main__':con = consumer("c1")con2 = consumer("c2")p = producer()

二:Greenlet

greenlet是一個用C實現的協程模塊,相比與python自帶的yield,它可以使你在任意函數之間隨意切換,而不需把這個函數先聲明為generator

使用greenlet實現協程

    from greenlet import greenletdef f1():print(12)gr2.switch()print(34)gr2.switch()def f2():print(56)gr1.switch()print(78)if __name__=='__main__':gr1 = greenlet(f1)gr2 = greenlet(f2)gr1.switch()     #手動切換,gevent是對greenlet的封裝,實現自動切換

運行結果:

12
56
34
78

三:Gevent

Gevent是一個第三方庫(需要額外自己安裝),可以輕松通過gevent實現并發同步或異步編程,在gevent中主要用到的模式是Greenlet,它是以C擴展模塊形式接入Python的輕量級協程。Greenlet全部運行在主程序操作系統的內部,被協作式調度

使用gevent庫實現協程

    import geventdef func1():print("func1 running")gevent.sleep(2)             # 內部函數實現io操作print("switch func1")def func2():print("func2 running")gevent.sleep(1)print("switch func2")def func3():print("func3  running")gevent.sleep(0.5)print("func3 done..")if __name__=='__main__':gevent.joinall([gevent.spawn(func1),gevent.spawn(func2),gevent.spawn(func3),])

運行結果:

func1 running
func2 running
func3  running
func3 done..
switch func2
switch func1

同步與異步的性能區別

    import geventdef task(pid):"""Some non-deterministic task"""gevent.sleep(0.5)print('Task %s done' % pid)def synchronous():for i in range(1, 10):task(i)def asynchronous():threads = [gevent.spawn(task, i) for i in range(10)]gevent.joinall(threads)if __name__ =='__main__':print('Synchronous:')synchronous()print('Asynchronous:')asynchronous()

運行結果:

Synchronous:
Task 1 done
Task 2 done
Task 3 done
Task 4 done
Task 5 done
Task 6 done
Task 7 done
Task 8 done
Task 9 done
Asynchronous:
Task 0 done
Task 1 done
Task 2 done
Task 3 done
Task 4 done
Task 5 done
Task 6 done
Task 7 done
Task 8 done
Task 9 done

將task函數封裝到Greenlet內部線程的gevent.spawn。 初始化的greenlet列表存放在數組threads中,此數組被傳給gevent.joinall 函數,后者阻塞當前流程,并執行所有給定的greenlet。執行流程只會在 所有greenlet執行完后才會繼續向下走。

遇到IO阻塞時會自動切換任務

from gevent import monkeymonkey.patch_all()
import gevent
from  urllib.request import urlopendef f(url):print('GET: %s' % url)resp = urlopen(url)data = resp.read()print('%d bytes received from %s.' % (len(data), url))if __name__=='__main__':gevent.joinall([gevent.spawn(f, 'https://www.python.org/'),gevent.spawn(f, 'https://www.yahoo.com/'),gevent.spawn(f, 'https://github.com/'),])

通過gevent實現單線程下的多socket并發

server端

import sys
import socket
import time
import geventfrom gevent import socket,monkey
monkey.patch_all()def server(port):s = socket.socket()s.bind(('0.0.0.0', port))s.listen(500)while True:cli, addr = s.accept()gevent.spawn(handle_request, cli)def handle_request(conn):try:while True:data = conn.recv(1024)print("recv:", data)conn.send(data)if not data:conn.shutdown(socket.SHUT_WR)except Exception as  ex:print(ex)finally:conn.close()
if __name__ == '__main__':server(8001)

client 端

import socketHOST = 'localhost'    # The remote host
PORT = 8001           # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
while True:msg = bytes(input(">>:"),encoding="utf8")s.sendall(msg)data = s.recv(1024)#print(data)print('Received', repr(data))
s.close()

并發100socket連接

import socket
import threadingdef sock_conn():client = socket.socket()client.connect(("localhost",8001))count = 0while True:#msg = input(">>:").strip()#if len(msg) == 0:continueclient.send( ("hello %s" %count).encode("utf-8"))data = client.recv(1024)print("[%s]recv from server:" % threading.get_ident(),data.decode()) #結果count +=1client.close()for i in range(100):t = threading.Thread(target=sock_conn)t.start()

原文鏈接:https://blog.csdn.net/qq_39112646/article/details/86776107
感謝作者分享!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/452704.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/452704.shtml
英文地址,請注明出處:http://en.pswp.cn/news/452704.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ffmpeg 0.6.3 代碼, 經過我努力,能夠在vs 2005 下單步調試代碼

1. ffmpeg-0.6.3_modify.7z 是修改后的ffmepg的代碼&#xff1b; 2.ffmpeg-0.6.3_srouce.tar.bz2 是ffmpeg原始代碼&#xff1b; 3.SDL-devel-1.2.15-VC.zip 是圖像顯示使用使用的sdl代碼&#xff1b; 4.w_cc_p_10.1.020.exe 是vc 2005 需要使用的編譯器&#xff1b…

克隆CentOS6虛擬機eth0被修改為eth1如何修改eth0

2019獨角獸企業重金招聘Python工程師標準>>> 直接修改 /etc/sysconfig/network-script/ifcfg-eth0 刪掉UUID HWADDR 配置靜態地址 然后&#xff1a; rm -rf  /etc/udev/rules.d/70-persistent-net.rules然后reboot 轉載于:https://my.oschina.net/hengbao666/blog/…

[Hnoi2013]消毒

Description 最近在生物實驗室工作的小T遇到了大麻煩。 由于實驗室最近升級的緣故&#xff0c;他的分格實驗皿是一個長方體,其尺寸為abc&#xff0c;a、b、c 均為正整數。為了實驗的方便&#xff0c;它被劃分為abc個單位立方體區域&#xff0c;每個單位立方體尺寸 為111。用(i,…

php按照文件名字排序,php readdir 排序問題,如何按照日期進行排序

目前是這么寫的&#xff1a;function posts_get($directory,$ext){if (is_dir($directory)) {$handle opendir($directory);while ($file readdir($handle)){$subdir $directory . / .$file;if ($file ! . && $file !.. && is_dir($subdir)){posts_get($sub…

關系模型的名詞

關系&#xff08;Relation&#xff09;一個關系對應通常說的一張表元組&#xff08;Tuple&#xff09;表中的一行即為一個元組屬性&#xff08;Attribute&#xff09;表中的一列即為一個屬性&#xff0c;給每一個屬性起一個名稱即屬性名主碼&#xff08;Key&#xff09;也稱碼鍵…

物理卷、卷組、邏輯卷

參考文章&#xff1a; 相關文獻 謝謝作者分享!

fibonacci數列的題目——劍指Offer

https://www.nowcoder.net/practice/c6c7742f5ba7442aada113136ddea0c3?tpId13&tqId11160&tPage1&rp1&ru/ta/coding-interviews&qru/ta/coding-interviews/question-ranking 大家都知道斐波那契數列&#xff0c;現在要求輸入一個整數n&#xff0c;請你輸出…

如何高效的編寫與同步博客 (.NET Core 小工具實現)

系列目錄 [如何高效的編寫與同步博客&#xff08;一&#xff09;- 編寫 ]如何高效的編寫與同步博客&#xff08;二&#xff09;- 快速發布到多個渠道一.前言 寫博客&#xff0c;可以帶給我們很多好處&#xff0c;比如可以讓我們結識更多志同道合的人&#xff1b;在寫博客過程中…

java appendable,org.eclipse.jetty.util.Utf8Appendable$NotUtf8Exception: Not valid UTF8

上傳文件奇怪的錯誤2016-10-14 11:00:52,254 nuoshang.bluejay.common.shiro.cache.RedisCache.put(RedisCache.java:54) DEBUG - SET nameshiro-activeSessionCache key70qv5bejsihmgot7hroqg6q0lv2016-10-14 11:00:52,254 nuoshang.bluejay.common.shiro.cache.LCache.fire(L…

Oracle高可用概述(HA與RAC的關系解惑)

1.你如何理解高可用的概念&#xff1f; 所謂的高可用HA就是當你的系統中的某個節點異常損壞了&#xff0c;系統還是可用狀態&#xff0c;還可以對外提供服務&#xff0c;不會因為你的節點丟失而整體癱瘓。 2.列出你知道的Oracle高可用產品&#xff0c;并作一些功能和應用場景上…

從github clone文件: Failed to receive SOCKS4 connect request ack.

安裝了代理&#xff0c;能上網&#xff0c;也能從github上下載文件&#xff0c;就是無法從github上clone文件&#xff0c; 查了很久資料后&#xff0c;終于發現使用sudo可以解決問題。不過&#xff0c;不知道原因是什么&#xff1f; 比如&#xff1a;git clone https://github.…

mxf高速發展和數字電影母版制作技術

1.實現MXF的諾言——格式只是邁向可互操作內容管理的一步 當把元數據加到數字內容的MXF&#xff08;素材交換格式&#xff09;標準通過EBU于2002年推出時&#xff0c;當時曾預期廣播機構將會迅速無縫地管理其所有來自不同廠家的制作、后期和分配系統上的數字內容。 六年過…

Android 路由實踐(二)

前言繼上一篇Android 路由實踐&#xff08;一&#xff09;之后&#xff0c;斷更已經差不多一個月&#xff0c;畢竟是年前的最后一個月&#xff0c;各種事情扎堆&#xff0c;直到近幾天才稍微閑下來&#xff0c;于是有了此文。簡單回顧下&#xff0c;上一篇文章中簡單介紹了三種…

php中newself(),在php代碼中新建對象用到的new self與new static有什么不同

我們在使用php代碼新建對象的時候&#xff0c;一般會用到new self與new static,那么它們在使用的時候區別在哪里&#xff1f;先說說new static(),new static與new self一樣&#xff0c;在php代碼中&#xff0c;它是用來新建一個對象的.那么他們之間的不同之處在哪里呢&#xff…

ORACLE rac集群概念和原理

參考文獻&#xff1a; 文獻一 文獻二 文獻三 謝謝作者分享&#xff01;

Python基礎-變量作用域

1.函數作用域介紹 函數作用域 Python中函數作用域分為4種情況&#xff1a; L&#xff1a;local&#xff0c;局部作用域&#xff0c;即函數中定義的變量&#xff1a;E&#xff1a;enclosing&#xff0c;嵌套的父級函數的局部作用域&#xff0c;即包含此函數的上級函數的局部作用…

視頻源常見接口介紹

在錄制和播放中&#xff0c;要通過接口實現文件的傳輸&#xff0c;下面介紹常用接口。 [AV IN/OUT/PHONES]&#xff1a;這是一個多功能的插孔&#xff0c;在菜單里可以設置其功能。當設置為[IN/OUT]時&#xff0c;此插孔可以輸入和輸出音頻以及視頻信號&#xff0c;用于連接電視…

php愛奇藝篩選標簽,三種排序 快速篩選好視頻_軟件資訊技巧應用-中關村在線

使用在線視頻播放器來觀看視頻&#xff0c;通常有可以分為有目標和無目標兩種。即是用戶如果定點找一部視頻和隨意查看喜歡的視頻&#xff0c;這兩種模式往往查找視頻的方法也是不一樣的。我們這里要和大家講解的是&#xff0c;用戶在沒有目標視頻的情況下&#xff0c;怎樣更快…