如何在没有选择的情况下实施反应堆? [英] how do you implement a reactor without a select?

查看:68
本文介绍了如何在没有选择的情况下实施反应堆?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直很好奇人们如何实现主循环(或者,在Twisted术语,反应堆中使用
)。所以我坐下来写了

以下简单的实现:


import itertools


class SimpleReactor(object ):


DELAY = 0.001#秒

def __init __(自我):

self._event = { } #action id - (预定时间,动作,args)

self._counter = itertools.count(1)#action id generator

self.running = False


def callLater(self,deltat,action,* args):

"""在deltat秒内安排带参数args的动作。

返回操作ID""

now = time.time()

i = self._counter.next()

self._event [i] = now + deltat,action,args

返回i


def cancelCallLater(self,action_id):

"取消action_id标识的行动"

del self._event [action_id]


def default_action(self):#to be被覆盖的

"在eac调用h圈在主循环中

time.sleep(self.DELAY)#跑得太快,休息一下


def cleanup_action(self ):#被覆盖

在主循环结束时调用


def manage_exc(self,e):

每次通话时调用

提高e


def dooneevent(个体经营):

Perfom预定行动 ;

now = time.time()

for i,(start_time,action,args)in self._event.items():

如果现在> = start_time:#是时候开始行动了

self.cancelCallLater(i)#不要再次运行

尝试:

动作(* args)

除了异常,e:

self.manage_exc(e)


def run(self):

"运行主循环>

self.running = True

尝试:

而self.running:

self.default_action()

self.dooneevent()

除KeyboardInterrupt外:

打印''通过CTRL-C停止''

终于:

self.cleanup_action()


def stop(self):

self.running = False


请注意我复制了Twisted术语,但

我没有看Twisted实现,因为我不想

使用select(我假设GUI mainloops也不使用它)。

诀窍I用于存储要在事件字典中执行的操作(由整数标识的
callables)和

如果当前时间更长则在mainlooop中运行它们预定的时间比



我必须在default_action中添加time.sleep(.001)来避免

消耗100%

循环中的CPU。

我想知道真正的主循环是否以这种方式完成以及多么糟糕/好的

此实现比较一个严肃的人。任何建议/提示/

建议

非常感谢。谢谢,


Michele Simionato

I have always been curious about how people implement mainloops (or,
in Twisted terminology, reactors). So I sit down and I wrote the
following simple implementation:

import itertools

class SimpleReactor(object):

DELAY = 0.001 # seconds

def __init__(self):
self._event = {} # action id -(scheduled time, action, args)
self._counter = itertools.count(1) # action id generator
self.running = False

def callLater(self, deltat, action, *args):
"""Schedule an action with arguments args in deltat seconds.
Return the action id"""
now = time.time()
i = self._counter.next()
self._event[i] = now + deltat, action, args
return i

def cancelCallLater(self, action_id):
"Cancel the action identified by action_id"
del self._event[action_id]

def default_action(self): # to be overridden
"Invoked at each lap in the mainloop"
time.sleep(self.DELAY) # don''t run too fast, rest a bit

def cleanup_action(self): # to be overridden
"Invoked at the end of the mainloop"

def manage_exc(self, e):
"Invoked at each call"
raise e

def dooneevent(self):
"Perfom scheduled actions"
now = time.time()
for i, (start_time, action, args) in self._event.items():
if now >= start_time: # it''s time to start the action
self.cancelCallLater(i) # don''t run it again
try:
action(*args)
except Exception, e:
self.manage_exc(e)

def run(self):
"Run the main loop"
self.running = True
try:
while self.running:
self.default_action()
self.dooneevent()
except KeyboardInterrupt:
print ''Stopped via CTRL-C''
finally:
self.cleanup_action()

def stop(self):
self.running = False

Notice that I copied the Twisted terminology, but
I did not look at Twisted implementation because I did not want to
use a select (I assume that the GUI mainloops do not use it either).
The trick I use is to store the actions to perform (which are
callables identified by an integer) in an event dictionary and
to run them in the mainlooop if the current time is greater than
the scheduled time.
I had to add a time.sleep(.001) call in the default_action to avoid
consuming 100%
of the CPU in the loop.
I wonder if real mainloops are done in this way and how bad/good is
this implementation compared to a serious one. Any suggestion/hint/
advice
is well appreciated. Thanks,

Michele Simionato

推荐答案

请注意,我复制了Twisted术语,但是
Notice that I copied the Twisted terminology, but

我没有看Twisted实现因为我不想

使用select(我假设GUI mainloops不使用它或者)。
I did not look at Twisted implementation because I did not want to
use a select (I assume that the GUI mainloops do not use it either).



你为什么这么认为?这是一个错误的假设。产生一个线程/进程

,直到操作系统因为要执行IO而将其唤醒,才能获得
go的正确方法。至少在unix中,IO是_everything_,也是鼠标移动和

键盘事件。最有可能的操作系统将有专门的API(或一些

包装器lib),允许反应器注册

不同种类的事件,包括计时器。但基本上,它是选择 - 我的意思是你

也可以很容易地提供一个计时器作为文件对象。不确定是否已经完成了'b $ =

Why do you assume that? It''s a wrong assumption. Yielding a thread/process
until the OS wakes it up because of IO to be performed is the proper way to
go. And at least in unix, IO is _everything_, also mouse-movements and
keyboard events. Most probably the OS will have specialized APIs (or some
wrapper lib has) that allow for reactor registration for events of
different kinds including timers. But basically, it''s select - I mean you
could easily offer a timer as a file-object as well. Not sure if that''s
done though.


我使用的技巧是存储要执行的操作(这些是

由一个整数标识的可调用字符串)和

如果当前时间大于预定时间的b / b
则在主循环中运行它们。

我必须在default_action中添加一个time.sleep(.001)调用,以避免

消耗100%

的CPU循环。

我想知道真正的主循环是否以这种方式完成,而且这个实现与一个严重的实施相比有多么糟糕/好。

。任何建议/提示/

建议

非常感谢。谢谢,
The trick I use is to store the actions to perform (which are
callables identified by an integer) in an event dictionary and
to run them in the mainlooop if the current time is greater than
the scheduled time.
I had to add a time.sleep(.001) call in the default_action to avoid
consuming 100%
of the CPU in the loop.
I wonder if real mainloops are done in this way and how bad/good is
this implementation compared to a serious one. Any suggestion/hint/
advice
is well appreciated. Thanks,



这没关系,但当然比它需要的更浪费 - 更好的是

完全授权给操作系统。


Diez

It''s ok, but of course more wasteful than it needs to be - better would be
full delegation to the OS.

Diez


Michele Simionato< mi *************** @ gmail.comwrote:
Michele Simionato <mi***************@gmail.comwrote:

我想知道真正的主循环是否以这种方式完成以及这个实现有多么糟糕/不好

严肃的。任何建议/提示/

建议都非常感谢。谢谢,
I wonder if real mainloops are done in this way and how bad/good is
this implementation compared to a serious one. Any suggestion/hint/
advice is well appreciated. Thanks,



Python的标准库中的模块可能会建议一个明显更好的

方法:当你提前知道未来的时候事件被安排,因此
相应地睡觉(而不是每毫秒轮询)。 sched'的

来源很简单,可以研究,它的架构很干净,而且b $ b足够强大,以至于它很容易扩展到其他情况,例如:其中

之前未计划的事件可能会从其他线程发送,

而不必黑客攻击。


具体来说,sched工具依赖注入DP:而不是

只调用time.time和time.sleep,它在初始化时接受这两个callables

。这使得在许多其他的b $ b定制中,很容易通过而不是time.sleep传递用户编码的可调用的b $ b(通常是一种绑定方法)来休眠。在

队列中等待超时(以便其他线程,通过在队列中将事件放入
问题,立即唤醒调度程序等,等等。

Alex

Module sched in Python''s standard library may suggest one clearly-better
approach: when you know in advance when future events are scheduled for,
sleep accordingly (rather than polling every millisecond). sched''s
sources are simple enough to study, and its architecture clean and
strong enough that it''s easy to extend to other cases, e.g. where
previously-unscheduled events may be delivered from other threads,
without necessarily hacking the sources.

Specifically, sched implements the Dependency Injection DP: rather than
just calling time.time and time.sleep, it accepts those two callables
upon initialization. This makes it easy, among many other
customizations, to pass instead of time.sleep a user-coded callable
(typically a bound method) that "sleeps" by a wait-with-timeout on a
Queue (so that other threads, by putting an event on the Queue in
question, immediately wake up the scheduler, etc, etc).
Alex


5月7日下午4:39,a ... @ mac.com(Alex Martelli)写道:
On May 7, 4:39 pm, a...@mac.com (Alex Martelli) wrote:

Michele Simionato< michele.simion ... @ gmail.comwrote:
Michele Simionato <michele.simion...@gmail.comwrote:

我想知道是否真正的主循环以这种方式完成,与严重的实施相比,这个实现有多糟糕/好。任何建议/提示/

建议都非常感谢。谢谢,
I wonder if real mainloops are done in this way and how bad/good is
this implementation compared to a serious one. Any suggestion/hint/
advice is well appreciated. Thanks,



Python的标准库中的模块可能会建议一个明显更好的

方法:当你事先知道未来的时候事件被安排,因此
相应地睡觉(而不是每毫秒轮询)。 sched'的

来源很简单,可以研究,它的架构很干净,而且b $ b足够强大,以至于它很容易扩展到其他情况,例如:其中

之前未计划的事件可能会从其他线程发送,

而不必黑客攻击。


具体来说,sched工具依赖注入DP:而不是

只调用time.time和time.sleep,它在初始化时接受这两个callables

。这使得在许多其他的b $ b定制中,很容易通过而不是time.sleep传递用户编码的可调用的b $ b(通常是一种绑定方法)来休眠。在

队列中等待超时(以便其他线程,通过在队列中将事件放入
问题,立即唤醒调度程序等,等等。


Alex


Module sched in Python''s standard library may suggest one clearly-better
approach: when you know in advance when future events are scheduled for,
sleep accordingly (rather than polling every millisecond). sched''s
sources are simple enough to study, and its architecture clean and
strong enough that it''s easy to extend to other cases, e.g. where
previously-unscheduled events may be delivered from other threads,
without necessarily hacking the sources.

Specifically, sched implements the Dependency Injection DP: rather than
just calling time.time and time.sleep, it accepts those two callables
upon initialization. This makes it easy, among many other
customizations, to pass instead of time.sleep a user-coded callable
(typically a bound method) that "sleeps" by a wait-with-timeout on a
Queue (so that other threads, by putting an event on the Queue in
question, immediately wake up the scheduler, etc, etc).

Alex



我知道sched(这是我看到的第一件事):问题

是sched

采用阻塞方法,它基本上需要线程,而我

想要

避免它们。 Diez B. Roggisch的回复更接近我的期望:

I know about sched (it was the first thing I looked at): the problem
is that sched
adopt a blocking approach and it basically requires threads, whereas I
wanted to
avoid them. Diez B. Roggisch''s reply is closer to my expectations:


>很可能操作系统将有专门的API(或一些
包装器lib已经允许反应器注册包括定时器在内的不同类型的事件。
>Most probably the OS will have specialized APIs (or some
wrapper lib has) that allow for reactor registration for events of different
kinds including timers.



但是我在Linux上处理

计时器时有什么样的专用API?

看起来这是我应该问第一个

时间的问题;)

Michele Simionato

But what kind of specialized API do I have at my disposition for
timers on Linux?
It looks like this is the question I should have asked the first
time ;)
Michele Simionato


这篇关于如何在没有选择的情况下实施反应堆?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆