twisted reactor calllater实现
1. calllater实现代码
测试源码:
from twisted.internet import reactor
from twisted.internet import defer
def func_1():
print('calllater测试')
time.sleep(5)
print('calllater结束')
# error handle
def test_deferred_a():
#d = test_retrurn_deferred()
reactor.callLater(4, func_1)
reactor.callLater(15, reactor.stop)
reactor.run()
if __name__ == '__main__':
test_deferred_a()
1.1. 第一步:调用calllater
reactor.callLater(3, d.callback, 8)
先找到calllater
# <twisted.internet.selectreactor.SelectReactor object at 0x000000CE3BFC72B0>
@implementer(IReactorCore, IReactorTime, IReactorPluggableResolver,
IReactorPluggableNameResolver, _ISupportsExitSignalCapturing)
class ReactorBase(object):
"""
Default base class for Reactors.
"""
def callLater(self, _seconds, _f, *args, **kw):
"""See twisted.internet.interfaces.IReactorTime.callLater.
"""
assert callable(_f), "%s is not callable" % _f
assert _seconds >= 0, \
"%s is not greater than or equal to 0 seconds" % (_seconds,)
tple = DelayedCall(self.seconds() + _seconds, _f, args, kw,
self._cancelCallLater,
self._moveCallLaterSooner,
seconds=self.seconds)
self._newTimedCalls.append(tple)
return tple
DelayedCall基本上可以把它当作一个中间类,用于保存一些信息。
结果就是向self._newTimedCalls添加一个定时调用
self._newTimedCalls.append(tple)
可以看一下它的具体内容
_newTimedCalls= <class 'list'>: [<twisted.internet.base.DelayedCall object at 0x000000CE3C2EA668>]
1.2. 第二步
reactor.run()
跳过一些前置处理内容,直接到mainloop
def mainLoop(self):
while self._started:
try:
while self._started:
# Advance simulation time in delayed event
# processors.
self.runUntilCurrent()
t2 = self.timeout()
t = self.running and t2
self.doIteration(t)
except:
log.msg("Unexpected error in main loop.")
log.err()
else:
log.msg('Main loop terminated.')
进入self.runUntilCurrent()
def runUntilCurrent(self):
"""
运行所有挂起的calls
Run all pending timed calls.
"""
if self.threadCallQueue:
# Keep track of how many calls we actually make, as we're
# making them, in case another call is added to the queue
# while we're in this loop.
count = 0
total = len(self.threadCallQueue)
for (f, a, kw) in self.threadCallQueue:
try:
f(*a, **kw)
except:
log.err()
count += 1
if count == total:
break
del self.threadCallQueue[:count]
if self.threadCallQueue:
self.wakeUp()
# insert new delayed calls now
self._insertNewDelayedCalls()
now = self.seconds()
while self._pendingTimedCalls and (self._pendingTimedCalls[0].time <= now):
call = heappop(self._pendingTimedCalls)
if call.cancelled:
self._cancellations-=1
continue
if call.delayed_time > 0:
call.activate_delay()
heappush(self._pendingTimedCalls, call)
continue
try:
call.called = 1
call.func(*call.args, **call.kw)
except:
log.deferr()
if hasattr(call, "creator"):
e = "\n"
e += " C: previous exception occurred in " + \
"a DelayedCall created here:\n"
e += " C:"
e += "".join(call.creator).rstrip().replace("\n","\n C:")
e += "\n"
log.msg(e)
if (self._cancellations > 50 and
self._cancellations > len(self._pendingTimedCalls) >> 1):
self._cancellations = 0
self._pendingTimedCalls = [x for x in self._pendingTimedCalls
if not x.cancelled]
heapify(self._pendingTimedCalls)
if self._justStopped:
self._justStopped = False
self.fireSystemEvent("shutdown")
进入self._insertNewDelayedCalls()
def _insertNewDelayedCalls(self):
for call in self._newTimedCalls:
if call.cancelled:
self._cancellations-=1
else:
call.activate_delay()
heappush(self._pendingTimedCalls, call)
self._newTimedCalls = []
从self._newTimedCalls中获取DelayedCall()实例,放入self._pendingTimedCalls
在runUntilCurrent中会调用self._pendingTimedCallsk列表相关对象,也就是执行func_1.
2. 其它
2.1. 代码解析1
heappush(self._pendingTimedCalls, call)
函数heappush源自heapq.py
def heappush(heap, item):
"""Push item onto heap, maintaining the heap invariant."""
heap.append(item)
_siftdown(heap, 0, len(heap)-1)
简单点说,它会构建一个有序堆,默认最小堆。
在构建有序堆过程中肯定是要比较int类型了,但call是一个类。
这里要回顾python类的特殊方法了,已有文档,不赘述。
call是DelayedCall类的实例,查看相关代码。
def __le__(self, other):
"""
Implement C{<=} operator between two L{DelayedCall} instances.
Comparison is based on the C{time} attribute (unadjusted by the
delayed time).
"""
return self.time <= other.time
def __lt__(self, other):
"""
Implement C{<} operator between two L{DelayedCall} instances.
Comparison is based on the C{time} attribute (unadjusted by the
delayed time).
"""
return self.time < other.time