不等待函数调用的方法

15

请问是否有一种方法可以调用函数/方法(最好是在Python或Java中),并在不等待它的情况下继续执行。

例如:

def a():
    b()  #call a function, b()
    return "something"

def b():
    #something that takes a really long time

2
请查看https://dev59.com/bEbRa4cB1Zd3GeqPxBdJ,以获取有关在Python中使用线程的教程链接。 - gpoo
5
顺便提一句,运行而不等待结果的方法可以简单地称为“异步”。在您进行研究时可能会有所帮助。 - andycam
6个回答

27

在新线程中运行它。了解Java多线程这里和Python多线程这里

Java示例:

错误的方式......通过子类化Thread

new Thread() {
    public void run() {
        YourFunction();//Call your function
    }
}.start();

通过提供Runnable实例的方式,正确地...

Runnable myrunnable = new Runnable() {
    public void run() {
        YourFunction();//Call your function
    }
}

new Thread(myrunnable).start();//Call it when you need to run the function

1
请不要鼓励任何人直接子类化Thread,这几乎从来不是必要的(如果确实需要,该人员将知道他们在做什么而无需SO的帮助),这是一种不良实践,并可能导致一些令人惊讶的错误。 - Voo
我已经自作主张地注释了答案...因为这很重要。 - Stephen C
@StephenC 感谢您的编辑,但为什么子类化线程是错误的呢? - Ashwin Singh
3
@Ashwin,首先,可运行对象通常不是一般的线程(其他人不太可能将其用作一般的线程),但真正的问题是,您的类突然继承了几个您可能没有考虑过的方法,并且基类可能会做出一些令人惊讶的事情。例如,线程使用实例的对象作为锁并在其上等待 - 因此,如果您有一个同步方法,那可能会导致一些意外情况。 - Voo

6

正如其他答案中所提到的,从Python中,您可以将函数放入新线程(不太好,因为在CPython中使用线程并没有多大优势),或者使用Multiprocessing将其放入另一个进程中。

from multiprocessing import Process

def b():
    # long process

def a():
    p = Process(target=b) 
    p.start()
    ...
a()

(正如monkut的回答中所述。)但是Python的装饰器允许我们将样板代码隐藏起来,以一种在调用时你只“看到”普通函数调用的方式。在下面的示例中,我创建了“parallel”装饰器 - 只需在任何函数之前放置它,它将在调用时自动在单独的进程中运行:
from multiprocessing import Process
from functools import partial

from time import sleep

def parallel(func):
    def parallel_func(*args, **kw):
        p = Process(target=func, args=args, kwargs=kw)
        p.start()
    return parallel_func

@parallel
def timed_print(x=0):
    for y in range(x, x + 10):
        print y
        sleep(0.2)



def example():
    timed_print(100)
    sleep(0.1)
    timed_print(200)
    for z in range(10):
        print z
        sleep(0.2)


if __name__ == "__main__":
    example()

运行此代码片段,会得到以下结果:
[gwidion@caylus Documents]$ python parallel.py 
100
0
200
101
1
201
102
2
202
103
3
203
104
4
204
105
5
205
106
6
206
107
7
207
108
8
208
109
9
209
[gwidion@caylus Documents]$ 

4

在Python中使用多进程

from multiprocessing import Process

def b():
    # long process

p = Process(target=b) 
p.start()

3
在Java中,有一个标准的习惯用法:创建一个线程并启动它。
new Thread() {
    @Override
    public void run() {
        callMyFunction();
    }
}.start();

或者您可以创建一个Runnable并将其传递给线程:

Runnable caller = new Runnable() {
    @Override
    public void run() {
        callMyFunction();
    }
}

new Thread(caller).start();

你的第一选项是否在后台运行,无需等待执行? - R15
1
@Arvindraja - 是的。这两个选项的行为是相同的。 - Ted Hopp

1
最好先使用ExecutorService,而不是直接使用原始线程。 它提供了池化、完成检测,并且还有一些子类也具有一些调度功能。例如:
...
// Create a simple instance with a single thread in the pool
ExecutorService executor = Executors.newFixedThreadPool(1); 
...
Future<Integer> future = executor.submit(new Callable<Integer>() {
    @Override
    public Integer call() {
        return YourFunction();
    }
});
...

// To wait for YourFunction() to finish, and get the result:
Integer result = future.get();

您可以向ExecutorService提交尽可能多的异步任务;它们将在并行或顺序执行,具体取决于您选择的实现方式、后备线程池中的线程数量等。


0

由于os.fork在某些Windows系统中无法有效工作,因为操作系统有限制,所以jsbueno的答案并不适用于所有Windows系统。您需要在那里使用多线程来实现相同的效果。

请找到与jsbueno答案相同的代码,但使用多线程而不是多进程(Python 3版本)

from threading import Thread

from time import sleep

def thread_parallel(func):
    def parallel_func(*args, **kw):
        p = Thread(target=func, args=args, kwargs=kw)
        p.daemon = True
        p.start()
    return parallel_func

@thread_parallel
def timed_print(x=0):
    for y in range(x, x + 10):
        print(y)
        sleep(0.2)


def example():
    timed_print(100)
    sleep(0.1)
    timed_print(200)
    for z in range(10):
        print(z)
        sleep(0.2)


if __name__ == "__main__":
    example()

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