如何同时运行多个函数?

77

我想同时运行两个函数。

def func1():
    print('Working')

def func2():
    print('Working')

func1()
func2()

有人知道如何做到这一点吗?


3
可能是Python:如何并行运行Python函数?的重复。 - OrangeDog
13个回答

127

执行以下操作:

from threading import Thread

def func1():
    print('Working')

def func2():
    print("Working")

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

28
由于全局解释器锁的存在,即使相关计算机有多个CPU,它们也不能完全同时执行。他可能想知道这一点。http://wiki.python.org/moin/GlobalInterpreterLock - Jonas Elfström
1
@joaquin -- 你是对的,抱歉我忘记在复制粘贴后删除函数执行。 - chrisg
7
函数有返回值时,如何获得结果? - stallingOne
4
没必要使用两个导入语句,直接使用第二个即可。 - Federico Rubbi
5
如何向函数提供参数? - MilkyWay90
显示剩余5条评论

16

线程方面的回答很好,但您需要更具体地说明您想要做什么。

如果您有两个使用大量CPU的函数,在CPython中使用线程可能无济于事。那么,您可能需要查看多进程模块或者可能您想使用jython/IronPython。

如果CPU性能是问题所在,您甚至可以使用(非线程化的)C来实现,并且比在Python中并行执行两个任务获得更大的速度提升。

如果没有更多信息,很难给出一个好的答案。


12

使用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()])替换为:

如果func1()func2()都有返回结果,则需要对上述代码进行一些修改,用以下代码替换ray.get([func1.remote(),func2.remote()])

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

相比于使用multiprocessing模块或多线程,使用Ray具有多个优点。特别是,相同的代码既可以在单台机器上运行,也可以在一群机器上运行。

更多关于Ray的优点请参见这篇相关文章


4

一种看起来可以让两个函数同时运行的选项是使用threading模块(示例在this答案中)。

然而,正如Python官方文档页面所描述的那样,它存在一定的延迟。尝试使用更好的模块multiprocessing

此外,还有其他可用于异步执行(两个代码片段同时工作)的Python模块。关于它们的一些信息和选择帮助,您可以阅读this 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绑定任务,则线程仍然是适当的模型。


我在每个print()函数的末尾附加了time.time(),并将循环限制为9次。这是我在终端中看到的内容:('a', 1509314761.857559) ('a', 1509314761.857664) ('a', 1509314761.85767) ('a', 1509314761.857675) ('a', 1509314761.85768) ('a', 1509314761.857685) ('a', 1509314761.85769) ('a', 1509314761.857695) ('a', 1509314761.857699) ('b', 1509314761.858138) ('b', 1509314761.858224) ('b', 1509314761.858229) ('b', 1509314761.858234) ('b', 1509314761.858239) ('b', 1509314761.858244) ('b', 1509314761.858249) ('b', 1509314761.858253) ('b', 1509314761.858258) - weefwefwqg3
即使使用多进程,它也不是真正的并发,对吧?一个运行在另一个之后。 - weefwefwqg3
@weefwefwqg3,请查看我的回答中的链接以获取有关模块的详细信息。您也可以自行查看,但官方文档应该会有解释。 - Edward
我不确定这是否是一个错误,但对我来说,多进程无法正常工作。thr1 = Process(target=run_foo(), args=()) 这一行本不应该创建线程 *(因为我没有运行 thr1.start())*,但实际上它创建了一个线程,因此应该由 run_foo() 启动的进程会窃取执行权,导致无法进行多线程处理。 - Hi-Angel

3

与多进程不同,线程模块可以同时工作,但时间略有偏差。下面的代码会分别调用不同的函数来打印“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

不确定是否有一种方法可以纠正这个问题,或者这是否有关紧要。只是我注意到的一些事情。


2

如果您希望等待两个函数都完成:

wait

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()

1
尝试这个。
from threading import Thread

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

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

t1.start()
t2.start()

1
为此提供一个见解,说明这如何解决原帖作者的需求。 - NitinSingh
1
如何使用返回语句实现此功能,只有在函数中具有print语句时才能正常工作。 - taga

1

在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

[注意]:


1

以下代码可以同时运行两个函数:

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

0

我认为你试图传达的内容可以通过多进程实现。但是,如果你想通过线程来做,你也可以这样做。 这可能会有所帮助。

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()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接