繁体   English   中英

如何同时运行多个函数?

[英]How to run multiple functions at the same time?

我试图同时运行 2 个函数。

def func1():
    print('Working')

def func2():
    print('Working')

func1()
func2()

有谁知道如何做到这一点?

做这个:

from threading import Thread

def func1():
    print('Working')

def func2():
    print("Working")

if __name__ == '__main__':
    Thread(target = func1).start()
    Thread(target = func2).start()

关于线程的答案很好,但您需要更具体地了解您想要做什么。

如果您有两个都使用大量 CPU 的函数,线程(在 CPython 中)可能会让您无处可去。 然后你可能想看看多处理模块,或者你可能想使用 jython/IronPython。

如果 CPU 受限的性能是原因,你甚至可以在(非线程)C 中实现一些东西,并且比在 python 中做两个并行的东西获得更大的加速。

没有更多信息,想得出一个好的答案并不容易。

这可以通过Ray优雅地完成,这是一个允许您轻松并行化和分发 Python 代码的系统。

要并行化您的示例,您需要使用@ray.remote decorator定义您的函数,然后使用.remote调用它们。

import ray

ray.init()

# Define functions you want to execute in parallel using 
# the ray.remote decorator.
@ray.remote
def func1():
    print("Working")

@ray.remote
def func2():
    print("Working")

# Execute func1 and func2 in parallel.
ray.get([func1.remote(), func2.remote()])

如果func1()func2()返回结果,则需要稍微重写上面的代码,将ray.get([func1.remote(), func2.remote()])替换为:

ret_id1 = func1.remote()
ret_id2 = func1.remote()
ret1, ret2 = ray.get([ret_id1, ret_id2])

多处理模块或使用多线程相比,使用 Ray 有许多优点。 特别是,相同的代码将在单台机器和机器集群上运行。

有关 Ray 的更多优势,请参阅此相关帖子

一个选项,看起来像它使在相同的运行两种功能
time ,正在使用threading模块(答案中的示例)。

但是,它有一个小的延迟,作为官方 Python 文档
描述。 一个更好的尝试使用的模块是multiprocessing

此外,还有其他 Python 模块可用于异步执行(两段代码同时工作)。 有关它们的一些信息并帮助选择一个,您可以阅读Stack Overflow 问题。

另一个用户对threading模块的评论

他可能想知道,因为全局解释器锁
即使机器在,它们也不会在完全相同的时间执行
问题有多个 CPU。 wiki.python.org/moin/GlobalInterpreterLock

– Jonas Elfström 2010 年6 月 2 日,11:39

引用来自关于threading模块不起作用的文档

CPython 实现细节:在 CPython 中,由于全局解释器
锁,一次只有一个线程可以执行 Python 代码(即使
某些面向性能的库可能会克服此限制)。

如果你想让你的应用更好地利用多核机器的计算资源,建议你使用 multiprocessing 或 concurrent.futures.ProcessPoolExecutor。
然而,线程仍然是一个合适的模型,如果你
想要同时运行多个 I/O 密集型任务。

与多进程不同,线程模块确实同时工作,但时间有点偏离。 下面的代码打印“1”和“2”。 它们分别被不同的函数调用。 我确实注意到当打印到控制台时,它们的时间会略有不同。

from threading import Thread

def one():
    while(1 == num):
        print("1")
        time.sleep(2)
    
def two():
    while(1 == num):
        print("2")
        time.sleep(2)


p1 = Thread(target = one)
p2 = Thread(target = two)

p1.start()
p2.start()

输出:(注意空间用于打印之间的等待)

1
2

2
1

12
   
21

12
   
1
2

不确定是否有办法纠正这个问题,或者它是否重要。 只是我注意到的一点。

尝试这个

from threading import Thread

def fun1():
    print("Working1")
def fun2():
    print("Working2")

t1 = Thread(target=fun1)
t2 = Thread(target=fun2)

t1.start()
t2.start()

我认为您要传达的内容可以通过多处理来实现。 但是,如果您想通过线程进行操作,则可以执行此操作。 这可能有帮助

from threading import Thread
import time

def func1():
    print 'Working'
    time.sleep(2)

def func2():
    print 'Working'
    time.sleep(2)

th = Thread(target=func1)
th.start()
th1=Thread(target=func2)
th1.start()

使用 APscheduler 测试:

from apscheduler.schedulers.background import BackgroundScheduler
import datetime

dt = datetime.datetime
Future = dt.now() + datetime.timedelta(milliseconds=2550)  # 2.55 seconds from now testing start accuracy

def myjob1():
    print('started job 1: ' + str(dt.now())[:-3])  # timed to millisecond because thats where it varies
    time.sleep(5)
    print('job 1 half at: ' + str(dt.now())[:-3])
    time.sleep(5)
    print('job 1 done at: ' + str(dt.now())[:-3])
def myjob2():
    print('started job 2: ' + str(dt.now())[:-3])
    time.sleep(5)
    print('job 2 half at: ' + str(dt.now())[:-3])
    time.sleep(5)
    print('job 2 done at: ' + str(dt.now())[:-3])

print(' current time: ' + str(dt.now())[:-3])
print('  do job 1 at: ' + str(Future)[:-3] + ''' 
  do job 2 at: ''' + str(Future)[:-3])
sched.add_job(myjob1, 'date', run_date=Future)
sched.add_job(myjob2, 'date', run_date=Future)

我得到了这些结果。 这证明它们是同时运行的。

 current time: 2020-12-15 01:54:26.526
  do job 1 at: 2020-12-15 01:54:29.072  # i figure these both say .072 because its 1 line of print code
  do job 2 at: 2020-12-15 01:54:29.072
started job 2: 2020-12-15 01:54:29.075  # notice job 2 started before job 1, but code calls job 1 first.
started job 1: 2020-12-15 01:54:29.076  
job 2 half at: 2020-12-15 01:54:34.077  # halfway point on each job completed same time accurate to the millisecond
job 1 half at: 2020-12-15 01:54:34.077
job 1 done at: 2020-12-15 01:54:39.078  # job 1 finished first. making it .004 seconds faster.
job 2 done at: 2020-12-15 01:54:39.091  # job 2 was .002 seconds faster the second test

如果您还想等到两个功能都完成:

from threading import Thread

def func1():
    print 'Working'

def func2():
    print 'Working'

# Define the threads and put them in an array
threads = [
    Thread(target = self.func1),
    Thread(target = self.func2)
]

# Func1 and Func2 run in separate threads
for thread in threads:
    thread.start()

# Wait until both Func1 and Func2 have finished
for thread in threads:
    thread.join()

在 python 中同时运行多个函数的另一种方法是使用我在答案中看不到的asyncio

import asyncio

async def func1():
    for _ in range(5):
        print(func1.__name__)
        await asyncio.sleep(0)  # switches tasks every iteration.

async def func2():
    for _ in range(5):
        print(func2.__name__)
        await asyncio.sleep(0)

tasks = [func1(), func2()]
await asyncio.gather(*tasks)

出去:

func1
func2
func1
func2
func1
func2
func1
func2
func1
func2

[注意]:

下面的代码可以并行运行 2 个函数:

from multiprocessing import Process

def test1():
    print("Test1")

def test2():
    print("Test2")

if __name__ == "__main__":
    process1 = Process(target=test1)
    process2 = Process(target=test2)
    process1.start()
    process2.start()
    process1.join()
    process2.join()

结果:

Test1
Test2

并且,下面这两组代码可以同时运行两个函数:

from threading import Thread

def test1():
    print("Test1")

def test2():
    print("Test2")

thread1 = Thread(target=test1)
thread2 = Thread(target=test2)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
from operator import methodcaller
from multiprocessing.pool import ThreadPool

def test1():
    print("Test1")

def test2():
    print("Test2")

caller = methodcaller("__call__")
ThreadPool().map(caller, [test1, test2])

结果:

Test1
Test2

并且,下面的代码可以同时异步运行 2 个async函数:

import asyncio

async def test1():
    print("Test1")
        
async def test2():
    print("Test2")
        
async def call_tests():
    await asyncio.gather(test1(), test2())

asyncio.run(call_tests())

结果:

Test1
Test2

我可能是错的但是:使用这段代码:

def function_sleep():
    time.sleep(5)

start_time = time.time()
        p1=Process(target=function_sleep)
        p2=Process(target=function_sleep)
        p1.start()
        p2.start()
end_time = time.time()

我花了一些时间,我希望得到 5/6 秒,而它总是需要传递给 function 睡眠的参数的两倍(在这种情况下为 10 秒)。 怎么了?

对不起伙计们,正如之前评论中提到的,需要调用“join()”。 这非常重要!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM