我在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 还为multiprocessing
和threading
提供了更多较低级别的接口。如果您正在查看 I/O 密集型任务,那么还有另一种方法可用,asyncio
,这可能是一种替代方案:有一点学习曲线,您可能需要重组您的函数,但这可能是值得的。