multithreading.Pool.apply_async()立即返回,不执行回调

时间:2018-02-09 02:25:11

标签: python multithreading python-3.x asynchronous multiprocessing

来自函数sync_lister()的控制台输出:

20203.161 ms
19930.7166 ms
21279.1429 ms
18988.5079 ms
17724.5125 ms
11358.8549 ms
36164.6077 ms
20183.306099999998 ms
14238.174599999998 ms
20383.551 ms

Process finished with exit code 0

很好,这就是我的期望。现在我想把它放在一个工作池中,并以大约4倍的速度完成它。

我以为我做得恰到好处。为什么我没有任何输出?

运行async_lister()时没有控制台输出,应用程序立即返回。

完整的代码如下。如果您需要ffprobe包装器或其他任何内容的来源,请告诉我。

#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import os

from utilities import glob_from
from controller import run_ffprobe
from multiprocessing import Pool

INPUT_DIR = "C:/Users/spike/Music/Deezloader"


def get_duration(metadata):
    return float(metadata.get("format", {}).get("duration", 0)) * 100


def example_callback(metadata):
    print(get_duration(metadata), "ms")


args_list = [(os.path.join(INPUT_DIR, path),) for path in glob_from(INPUT_DIR, "flac")[0:10]]
# Example: [('C:/Users/spike/Music/Deezloader\\AWOLNATION - Handyman\\1 - AWOLNATION - Handyman.flac',), ...]


def sync_lister():
    for args in args_list:
        example_callback(run_ffprobe(*args))


def async_lister():
    pool = Pool(4)  # Creates four threads, four items from "args" will be run with "run_ffprobe" at a time

    pool.apply_async(run_ffprobe, args=args_list, callback=example_callback)
    # Set the target to "run_ffprobe", and each item in "args_list" will be unpacked as arguments
    # and sent to that function when a pool worker is free

    pool.close()  # Close the pool, no more process can be added
    pool.join()  # Wait for all of the processes to complete


if __name__ == "__main__":
    sync_lister()  # Working
    async_lister()  # Not working

1 个答案:

答案 0 :(得分:1)

正如apply()/apply_async() documentation中所述,每次调用apply()apply_async()都相当于一次调用您传递的函数作为第一个参数(即run_ffprobe)。

在同步代码中,您将args_list的每个元素传递给单独的run_ffprobe()来电:

for args in args_list:
    example_callback(run_ffprobe(*args))

在您的异步代码中,您要求池计算:

example_callback(run_ffprobe(args_list))

这不是你想要它做的。您需要在循环中调用apply_async(),就像您在循环中调用run_ffprobe()一样。或者,您可以使用map_async(),但这只会使用整个结果列表调用一次回调。这似乎与您在同步代码中所做的不相符,但您可以重写回调以适应此模式,或使用functools.partial(map, example_callback)之类的内容作为map_async()的回调。