Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中执行延迟操作的最有效方法_Python_Multithreading_Python 3.4 - Fatal编程技术网

在Python中执行延迟操作的最有效方法

在Python中执行延迟操作的最有效方法,python,multithreading,python-3.4,Python,Multithreading,Python 3.4,考虑一个系统,在这个系统中,事件发生在不可预测的时间点。我希望能够执行一个“延迟”操作,在最后一个事件发生后执行一个固定的时间量X单位。如果事件是在最后X个时间单位内发生的唯一事件,则该事件被视为“最后一次”。在Python中最有效的方法是什么 我考虑过的一个解决方案是使用线程。Event: # This solution has the drawback that the deferred event may actually occur # up to 2*X units of time a

考虑一个系统,在这个系统中,事件发生在不可预测的时间点。我希望能够执行一个“延迟”操作,在最后一个事件发生后执行一个固定的时间量X单位。如果事件是在最后X个时间单位内发生的唯一事件,则该事件被视为“最后一次”。在Python中最有效的方法是什么

我考虑过的一个解决方案是使用
线程。Event

# This solution has the drawback that the deferred event may actually occur
# up to 2*X units of time after the last event.
# Also, it kinda sucks that the thread is basically polling once the first
# event comes in.


from threading import Thread
from threading import Event
import time
import sys


evt = Event()
die = False
X = 1


def thread_func_event():
    while True:
        evt.wait()
        if die:
            break

        while True:
            evt.clear()
            time.sleep(X)

            if not evt.is_set():
                # No more events came in. Good.
                break
            # Looks like more events came in. Let's try again.

            if die:
                return

        print('Deferred action performed.')
        sys.stdout.flush()


def event_occurred():
    evt.set()


t = Thread(target=thread_func_event)
t.start()

for _ in range(0, 1000000):
    event_occurred()
print('First batch of events done.')
sys.stdout.flush()

time.sleep(3)

for _ in range(0, 1000000):
    event_occurred()
print('Second batch of events done.')
sys.stdout.flush()

time.sleep(3)
die = True
evt.set()
t.join()

我以前做过类似的事情

import threading
import time

class waiter(object):
    def __init__(self, action, delay = 0.5, *args, **kwargs):
        self.action_lockout_timeout = threading.Thread()
        self.action_lockout_event   = threading.Event()
        self.action                 = action
        self.delay                  = delay
        self.action_prevent()

    def action_prevent(self):
        def action_enable():
            self.action_lockout_event.wait(self.delay)
            if not self.action_lockout_event._Event__flag:
                self.action()

        if self.action_lockout_timeout.isAlive():
            self.action_lockout_event.set()
            self.action_lockout_timeout.join()
        self.action_lockout_event.clear()
        self.action_lockout_timeout = threading.Thread(target = action_enable)
        self.action_lockout_timeout.setDaemon(True)
        self.action_lockout_timeout.start()

def thanks():
    print("Person 2: Thank you ...")

polite = waiter(thanks, 3)
print("Person 1: After you")
polite.action_prevent()
time.sleep(2)
print("Person 2: No, after you")
polite.action_prevent()
time.sleep(2)
print("Person 1: No I insist")
polite.action_prevent()
time.sleep(2)
print("Person 2: But it would be rude")
polite.action_prevent()
time.sleep(2)
print("---Akward Silence---")
time.sleep(2)
如果要运行带参数的函数,只需使用
lambda
表达式将其包装即可

def thanks(person):
    print("%s: Thank you ..." % person)

polite = waiter(lambda: thanks("Person 2"), 3)
编辑:

原来
threading.Event
相当慢。这里有一个解决方案,它将
事件
替换为
time.sleep
bool
。它还使用
\uuuuuuuuuuuuuuuuuuu
来加速属性访问

import sys
import threading
import time

class waiter(object):
    __slots__ = \
    [
        "action",
        "delay",
        "undelayed",
        "delay_timeout",
    ]
    def __init__(self, action, delay = 0.5, *args, **kwargs):
        self.action        = action
        self.delay         = delay
        self.undelayed     = False
        self.delay_timeout = threading.Thread(target = self.action_enable)
        self.delay_timeout.start()

    def action_prevent(self):
        self.undelayed = False

    def action_enable(self):
        while True:
            time.sleep(self.delay)
            if self.undelayed:
                self.action()
                break
            else:
                self.undelayed = True

def thanks():
    print("Person 2: Thank you ...")

polite = waiter(thanks, 1)
for _ in range(0, 1000000):
    polite.action_prevent()

print("First batch of events done.")
time.sleep(2)

这似乎没有那么有效,因为每次“中断”时,都会破坏当前线程,并创建一个新线程。是的,这有助于满足延迟时间保证,但我宁愿牺牲一些时间保证来获得更好的性能。考虑一下这个解决方案的性能,我在上面的代码中举例说明,其中有1000000个中断。好多了,但基本上,你似乎正在接近我的解决方案。您可以进行的下一个优化是有一个长时间运行的线程,此时您需要某种方式来“通知”线程。正如你所看到的,我用了一个事件。我从您的解决方案中得到的一个想法是,如果主线程能够以某种方式确定辅助线程是否仍在运行和循环,我可以避免调用Event.set,而是设置bool或其他指示中断的内容,我认为这样会更便宜。让我再考虑一下,是的,我建议避免
threading.Event
,因为它很慢。