[英]Best practice to “collect and execute in a bunch” in Python
I just fund myself implementing a timer-based version of "handle a list of events as a bunch" in order to safe resources - again - and I'm wondering whether there is a nice common pythonic approach.我只是资助自己实现一个基于计时器的“将事件列表作为一组处理”的版本,以保护资源 - 再次 - 我想知道是否有一个很好的通用 pythonic 方法。
You probably know this: you're handling recurring events like mouse movements, file system changes etc. and you have to do some calculation as a reaction to those events but it would be great if you could use a little break in the stream of events to handle them in a bunch.您可能知道这一点:您正在处理重复发生的事件,例如鼠标移动、文件系统更改等,并且您必须进行一些计算作为对这些事件的反应,但如果您可以在 stream 事件中使用一点中断,那就太好了成堆地处理它们。 Maybe because older events get invalidated by newer events (and it's enough to handle the oldest ones) or because events can somehow be squashed together.可能是因为较旧的事件被较新的事件无效(并且足以处理最旧的事件),或者因为事件可以以某种方式被挤压在一起。
Examples are: mouse movements (draw only latest position), "auto save" in editors or auto-sync on file systems, or (in my example) monitoring file system changes and re-compile something.示例包括:鼠标移动(仅绘制最新位置)、编辑器中的“自动保存”或文件系统上的自动同步,或(在我的示例中)监视文件系统更改并重新编译某些内容。
Usually I look up how to use a Timer
and think about how I could avoid an extra thread and come up with some semi-finished but complex solution for a - in my eyes - very simple problem.通常我会查看如何使用Timer
并思考如何避免额外的线程,并为一个在我看来非常简单的问题提出一些半成品但复杂的解决方案。 Lot of questions arise:出现很多问题:
threading.Timer
and start a thread doing the work)如何避免并发处理(例如,如果我使用threading.Timer
并启动一个线程来完成工作)What I'd like to have is something which works like this:我想要的是这样工作的东西:
timer = SomeContinuousTimer()
new_events = []
while True:
event = wait_for(inotify_adapter.event_gen(), timer.timeout())
if event == timer.TIMEOUT:
my_handler_func(new_events)
else:
new_events.append(event)
timer.restart(1500)
But wait_for
would have to act like select
and for this I'd need file descriptors and the above code is already a bit more than I would actually expect it to be.但是wait_for
必须像select
那样行事,为此我需要文件描述符,上面的代码已经比我实际预期的要多一些。
What I would be really glad about to have would be used like this:我真的很高兴会像这样使用:
bunch_handler = BunchHandler()
new_events = []
def read_events():
for event in inotify_adapter.event_gen():
new_events.append(event)
while True:
# will run `read_events` asynchronously until 1.5sec have passed since the
# last event
bunch_handler.read(read_fn=read_events, bunch_wait=1500)
handle_events(new_events)
Is this a typical scenario I should use async
/ await
for?这是我应该使用async
/ await
的典型场景吗? Are there frameworks for the case where async
is not an option?对于不能选择async
的情况,是否有框架? Is there an async framework for this exact scenario?是否有适用于这种确切场景的异步框架?
This is not nice but it does what I want and might act as an example which shows, what I'm talking about:)这不是很好,但它做了我想要的,并且可以作为一个例子来说明我在说什么:)
import asyncio
import time
async def event_collector(*, listener_fn, bunch_wait=1.0, max_wait=2.0):
"""Wait for (but don't handle) events and wait for a maximum of @bunch_wait seconds after the
last event before returning. Force return after @max_wait seconds"""
max_time_task = asyncio.Task(asyncio.sleep(max_wait))
while True:
resetable = asyncio.Task(asyncio.sleep(bunch_wait))
done, _ = await asyncio.wait(
{listener_fn.__anext__(), resetable, max_time_task},
return_when=asyncio.FIRST_COMPLETED)
if resetable in done or max_time_task in done:
return
resetable.cancel()
async def generate_events(events):
"""Simulates bursts of events with side-effects"""
while True:
for i in range(5):
await asyncio.sleep(.01)
events.append(i)
print("*" * len(events))
yield
await asyncio.sleep(3.200)
def handle_events(events):
"""Simulates an event handler operating on a given structure"""
print("Handle %d events" % len(events))
events.clear()
async def main():
new_events = []
t = time.time()
while True:
await event_collector(listener_fn=generate_events(new_events), bunch_wait=1.1, max_wait=2.2)
now = time.time()
print("%.2f" % (now - t))
t = now
handle_events(new_events)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
This approach has some shortcomings: * you need to listen for events asynchronously using async
* event_collector will return after max_wait
seconds regardless whether any events have been seen yet (so it acts like a timeout if no events occur) * instead of resetting a timer, a new one gets created every time这种方法有一些缺点: * 您需要使用async
侦听事件 * event_collector 将在max_wait
秒后返回,无论是否已经看到任何事件(因此如果没有事件发生,它就像超时) * 而不是重置计时器,每次都会创建一个新的
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.