国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

sleep函數(shù)——Gevent源碼分析

2019-11-14 17:07:51
字體:
供稿:網(wǎng)友

gevent是一個異步I/O框架,當(dāng)遇到I/O操作的時候,會自動切換任務(wù),從而能異步地完成I/O操作
但是在測試的情況下,可以使用sleep函數(shù)來讓gevent進(jìn)行任務(wù)切換。示例如下:

import geventdef test(id):    PRint('Test %s is running...' % id)    gevent.sleep(0)    print('Test %s is done!' % id)gevent.joinall([gevent.spawn(test, i) for i in range(2)])

該函數(shù)的執(zhí)行結(jié)果是:

Test 0 is running...Test 1 is running...Test 0 is done!Test 1 is done!

可見,sleep函數(shù)能讓gevent切換協(xié)程,進(jìn)行異步操作。
這次我想探究一下sleep函數(shù)的原理。

在了解sleep函數(shù)之前,我們需要了解一下gevent的運(yùn)行
在前面的文章中,我們知道了gevent有個主協(xié)程hub的概念,當(dāng)需要切換協(xié)程的時候,需要先回到hub,然后再由hub去切換。
其實主協(xié)程hub是一個特殊的協(xié)程Greenlet
當(dāng)gevent運(yùn)行的時候,gevent需要先創(chuàng)建一個主協(xié)程hub,并運(yùn)行hub的run函數(shù)(具體源碼在hub.py/run),比較簡單,核心代碼是loop.run(),這個run函數(shù)是Greenlet類中的run函數(shù),用來切入loop中的子協(xié)程,源碼在greenlet.py/run中。核心就是result = self._run(*self.args, **self.kwargs), _run函數(shù)用來執(zhí)行這個子協(xié)程的任務(wù)

sleep函數(shù)

在剛剛的示例代碼中,在sleep處設(shè)置斷點,進(jìn)行跟蹤。
首先,進(jìn)入sleep函數(shù),函數(shù)在hub.py中:

def sleep(seconds=0, ref=True):    hub = get_hub()	#獲得主協(xié)程hub對象    loop = hub.loop		#獲得主循環(huán)    if seconds <= 0:        waiter = Waiter()        loop.run_callback(waiter.switch)	#設(shè)置回調(diào)函數(shù)(即下次本協(xié)程執(zhí)行的地點)        waiter.get()    else:        hub.wait(loop.timer(seconds, ref=ref))

當(dāng)seconds=0的時候,loop.run_callback(waiter.switch)把當(dāng)前greenlet的switch注冊到loop中,設(shè)置為回調(diào)函數(shù),此時的loop是主協(xié)程hub下的loop。

sleep函數(shù)中最后調(diào)用了waiter.get()get函數(shù)簡化如下:

def get(self):	assert self.greenlet is None, 'This Waiter is already used by %r' % (self.greenlet, )	self.greenlet = getcurrent()	try:		return self.hub.switch()	finally:		self.greenlet = None

self.greenlet = getcurrent(): 把greenlet設(shè)置為當(dāng)前協(xié)程greenlet
return self.hub.switch(): 切換到主線程hub的主循環(huán), 然后主循環(huán)再切換到下一個greenlet協(xié)程
工作流程如圖:

總結(jié)

Gevent的工作原理(省略了執(zhí)行完協(xié)程之后的過程)如下:

  1. 程序啟動,需要創(chuàng)建主協(xié)程hub
  2. 主協(xié)程執(zhí)行hub.run()函數(shù),里面主要是執(zhí)行loop.run(),loop中是子協(xié)程,相當(dāng)于執(zhí)行子協(xié)程的run()函數(shù)
  3. 切換到子協(xié)程,執(zhí)行Greenlet.run()函數(shù)
  4. Greenlet.run()函數(shù)中,執(zhí)行到self._run()函數(shù),即執(zhí)行該協(xié)程的任務(wù),本例中為自己定義的test()函數(shù)
  5. 一直執(zhí)行到sleep(0)語句
  6. 在sleep()函數(shù)中保存回調(diào)的位置(即保存該協(xié)程執(zhí)行到的地方),調(diào)用waiter.get()函數(shù)
  7. waiter.get()函數(shù)將調(diào)用self.hub.switch()切回主協(xié)程hub
  8. hub.switch()將調(diào)用greenlet.switch()函數(shù):

    1. 如果即將切換的協(xié)程未執(zhí)行過run函數(shù),則執(zhí)行run函數(shù);
    2. 如果執(zhí)行過run函數(shù),則調(diào)用Waiter.switch()函數(shù)接著上次執(zhí)行的地方執(zhí)行

重復(fù)以上的過程,直至所有協(xié)程任務(wù)全部執(zhí)行完畢


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 左云县| 廉江市| 织金县| 鞍山市| 加查县| 米林县| 绥宁县| 胶州市| 迁安市| 上虞市| 夏河县| 吐鲁番市| 宿松县| 张掖市| 交城县| 静安区| 滁州市| 辽中县| 桃园市| 湟源县| 昆山市| 蛟河市| 吐鲁番市| 冷水江市| 枣强县| 信丰县| 容城县| 绥芬河市| 山丹县| 明溪县| 石屏县| 安多县| 苗栗县| 永胜县| 武汉市| 华坪县| 浙江省| 原阳县| 资溪县| 阜新市| 乌海市|