Python:如何让程序等到函数或方法完成

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22467338/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 00:59:42  来源:igfitidea点击:

Python: How to make program wait till function's or method's completion

pythonmultithreadingmultiprocessing

提问by alphanumeric

Often there is a need for the program to wait for a function to complete its work. Sometimes it is opposite: there is no need for a main program to wait. I've put a simple example. There are four buttons. Clicking each will call the same calculate() function. The only difference is the way the function is called.

程序经常需要等待一个函数完成它的工作。有时恰恰相反:主程序不需要等待。我举了一个简单的例子。有四个按钮。单击每个将调用相同的 calculate() 函数。唯一的区别是调用函数的方式。

  1. "Call Directly"button calls calculate() function directly. Since there is a 'Function End' print out it is evident that the program is waiting for the calculate function to complete its job.
  2. "Call via Threading"calls the same function this time using threading mechanism. Since the program prints out ': Function End' message immidiately after the button is presses I can conclude the program doesn't wait for calculate() function to complete. How to override this behavior? How to make program wait till calculate() function is finished?
  3. "Call via Multiprocessing"buttons utilizes multiprocessing to call calculate() function. Just like with threading multiprocessing doesn't wait for function completion. What statement we have to put in order to make it wait?

  4. "Call via Subprocess"buttons doesn't do anything since I didn't figure out the way to hook subprocess to run internal script function or method. It would be interesting to see how to do it...

  1. “直接调用按钮直接调用 calculate() 函数。由于有“函数结束”打印输出,很明显程序正在等待计算函数完成其工作。
  2. “通过线程调用”这次使用线程机制调用相同的函数。由于程序在按下按钮后立即打印出 ':Function End' 消息,我可以得出结论,该程序不会等待 calculate() 函数完成。如何覆盖这种行为?如何让程序等待到calculate() 函数完成?
  3. “通过多处理调用按钮利用多处理来调用计算()函数。就像线程多处理不等待函数完成一样。为了让它等待,我们必须发表什么声明?

  4. “通过子进程调用”按钮没有做任何事情,因为我没有找到挂钩子进程以运行内部脚本函数或方法的方法。看看怎么做会很有趣......

Example:

例子:

from PyQt4 import QtCore, QtGui    
app = QtGui.QApplication(sys.argv)


def calculate(listArg=None):
    print '\n\t Starting calculation...'
    m=0
    for i in range(50000000):
        m+=i
    print '\t ...calculation completed\n'


class Dialog_01(QtGui.QMainWindow):
    def __init__(self):
        super(Dialog_01, self).__init__()

        myQWidget = QtGui.QWidget()
        myBoxLayout = QtGui.QVBoxLayout()       

        directCall_button = QtGui.QPushButton("Call Directly")
        directCall_button.clicked.connect(self.callDirectly)      
        myBoxLayout.addWidget(directCall_button) 

        Button_01 = QtGui.QPushButton("Call via Threading")
        Button_01.clicked.connect(self.callUsingThreads)
        myBoxLayout.addWidget(Button_01)        

        Button_02 = QtGui.QPushButton("Call via Multiprocessing")
        Button_02.clicked.connect(self.callUsingMultiprocessing)
        myBoxLayout.addWidget(Button_02) 

        Button_03 = QtGui.QPushButton("Call via Subprocess")
        Button_03.clicked.connect(self.callUsingSubprocess)
        myBoxLayout.addWidget(Button_03) 


        myQWidget.setLayout(myBoxLayout)
        self.setCentralWidget(myQWidget)
        self.setWindowTitle('Dialog 01')

    def callUsingThreads(self):
        print '------------------------------- callUsingThreads() ----------------------------------'
        import threading
        self.myEvent=threading.Event()
        self.c_thread=threading.Thread(target=calculate)
        self.c_thread.start()  

        print "\n\t\t : Function End"


    def callUsingMultiprocessing(self):
        print '------------------------------- callUsingMultiprocessing() ----------------------------------'
        from multiprocessing import Pool

        pool = Pool(processes=3)
        try: pool.map_async( calculate, ['some'])
        except Exception, e: print e 

        print "\n\t\t : Function End"


    def callDirectly(self):
        print '------------------------------- callDirectly() ----------------------------------'
        calculate()
        print "\n\t\t : Function End"


    def callUsingSubprocess(self):
        print '------------------------------- callUsingSubprocess() ----------------------------------'
        import subprocess 
        print '-missing code solution'
        print "\n\t\t : Function End"


if __name__ == '__main__':
    dialog_1 = Dialog_01()
    dialog_1.show()
    dialog_1.resize(480,320)
    sys.exit(app.exec_())

采纳答案by Victor C. Martins

Use a queue: each thread when completed puts the result on the queue and then you just need to read the appropriate number of results and ignore the remainder:

使用队列:每个线程在完成时将结果放在队列中,然后您只需要读取适当数量的结果并忽略余数:

#!python3.3
import queue    # For Python 2.x use 'import Queue as queue'
import threading, time, random

def func(id, result_queue):
    print("Thread", id)
    time.sleep(random.random() * 5)
    result_queue.put((id, 'done'))

def main():
    q = queue.Queue()
    threads = [ threading.Thread(target=func, args=(i, q)) for i in range(5) ]
    for th in threads:
        th.daemon = True
        th.start()

    result1 = q.get()
    result2 = q.get()

    print("Second result: {}".format(result2))

if __name__=='__main__':
    main()

Documentation for Queue.get() (with no arguments it is equivalent to Queue.get(True, None):

Queue.get() 的文档(没有参数,它相当于 Queue.get(True, None):

    Queue.get([block[, timeout]])

Remove and return an item from the queue. If optional args block is true and timeout is None (the default), block if necessary until an item is available. If timeout is a positive number, it blocks at most timeout seconds and raises the Empty exception if no item was available within that time. Otherwise (block is false), return an item if one is immediately available, else raise the Empty exception (timeout is ignored in that case).

How to wait until only the first thread is finished in Python

如何等到 Python 中只有第一个线程完成

You can to use .join() method too. what is the use of join() in python threading

您也可以使用 .join() 方法。 python线程中join()有什么用

回答by Patrick Kantorski

I find that using the "pool" submodule within "multiprocessing" works amazingly for executing multiple processes at once within a Python Script.

我发现在“multiprocessing”中使用“pool”子模块非常适合在 Python 脚本中同时执行多个进程。

See Section: Using a pool of workers

请参阅部分:使用工人池

Look carefully at "# launching multiple evaluations asynchronously mayuse more processes" in the example. Once you understand what those lines are doing, the following example I constructed will make a lot of sense.

仔细看例子中的“#launch multiple evaluations asynchronously mayuse more processes”。一旦您了解了这些行的作用,我构建的以下示例就会很有意义。

import numpy as np
from multiprocessing import Pool

def desired_function(option, processes, data, etc...):
    # your code will go here. option allows you to make choices within your script
    # to execute desired sections of code for each pool or subprocess.

    return result_array   # "for example"


result_array = np.zeros("some shape")  # This is normally populated by 1 loop, lets try 4.
processes = 4
pool = Pool(processes=processes)
args = (processes, data, etc...)    # Arguments to be passed into desired function.

multiple_results = []
for i in range(processes):          # Executes each pool w/ option (1-4 in this case).
    multiple_results.append(pool.apply_async(param_process, (i+1,)+args)) # Syncs each.

results = np.array(res.get() for res in multiple_results)  # Retrieves results after
                                                           # every pool is finished!

for i in range(processes):
    result_array = result_array + results[i]  # Combines all datasets!

The code will basically run the desired function for a set number of processes. You will have to carefully make you're function can distinguish between each process (hence why I added the variable "option".) Additionally, it doesn't have to be an array that is being populated in the end, but for my example thats how I used it. Hope this simplifies or helps you better understand the power of multiprocessing in Python!

代码基本上会为一定数量的进程运行所需的功能。您必须小心地使您的函数可以区分每个进程(因此我添加了变量“选项”。)此外,它不必是最后填充的数组,但对于我的示例这就是我如何使用它。希望这可以简化或帮助您更好地理解 Python 中多处理的强大功能!