线程中的 Python 返回元组



我在python中遇到了一个棘手的问题。这是我所拥有的。 首先,我有一个装饰器,我用它来为每个函数获取两个值,时间和结果。在我得到这些数字后,我使用python日志记录来存储时间。 现在我想同时运行两个函数并获取这些值。 最简单的方法是什么?

装饰:

def my_dec(func):
def wrapper(*args):
start_time = datetime.datetime.now().replace(microsecond=0)
result = func(*arg)
end_time  = datetime.datetime.now().replace(microsecond=0)
time = end_time - start_time
return time, result
return wrapper

功能1:

@my_dec
def get_taskbar_tooltip_message(timeout=10):
#This function calls another functions which waits and return value at a given timeout
#Returns string

功能2:

@my_dec
def check_pis(timer=200, status="start"):
#This function also calls other functions, which takes some time
#Returns bool

现在我想同时运行两个函数并获取这些值。

您可以从标准库的concurrent.futures模块中的高级工具开始。

处理是真正的并行处理:

import time
from functools import wraps
from concurrent.futures import ProcessPoolExecutor as Executor
def my_dec(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
end = time.perf_counter()
return end - start, result
return wrapper
@my_dec
def get_taskbar_tooltip_message(timeout=10):
time.sleep(3)
return "a string"
@my_dec
def check_pis(timer=200, status="start"):
time.sleep(5)
return True
if __name__ == "__main__":
with Executor() as exec:
start = time.perf_counter()
result_1 = exec.submit(get_taskbar_tooltip_message)
result_2 = exec.submit(check_pis)
print(result_1.result(), result_2.result())
end = time.perf_counter()
print(end - start)

几点评论:

  • 我用似乎更适合手头任务的time.perf_counter()替换了datetime.datetime.now()
  • 正如@Booboo所指出的:使用wraps是一种很好的做法。这在这里相当重要:没有它,多处理将失败(由于脱洗错误)。
  • 我在关键字参数的情况下用**kwargs放大了wrapper签名(@Booboo也指出了)。

线程看起来很相似,只是使用另一种类型的Executor

import time
from functools import wraps
from concurrent.futures import ThreadPoolExecutor as Executor
...
with Executor() as exec:
start = time.perf_counter()
result_1 = exec.submit(get_taskbar_tooltip_message)
result_2 = exec.submit(check_pis)
print(result_1.result(), result_2.result())
end = time.perf_counter()
print(end - start)

这里不需要if __name__ == "__main__":。线程不会脱离当前进程,因此它不是真正的并行,但它仍然非常有用。

选择哪种并发方法取决于您的用例:多处理更适合 CPU 密集型任务,而线程处理可能更适合 I/O 密集型任务。(Python 还为multiprocessingthreading提供了更多较低级别的接口。如果您正在查看 I/O 密集型任务,那么还有另一种方法可用,asyncio,这可能是一种替代方案:有一点学习曲线,您可能需要重组您的函数,但这可能是值得的。

最新更新