如何使用 concurrent.future 池线程执行器为 Subprocess.run 设置 shell=True

How to set shell=True for a Subprocess.run with a concurrent.future Pool Threading Executor

我尝试在 Python 中使用 concurrent.future 多线程和 subprocess.run 来启动外部 Python 脚本。但是我在 subprocess.run().

shell=True 部分遇到了一些麻烦

这里是外部代码的例子,姑且称之为test.py:

#! /usr/bin/env python3

import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-x', '--x_nb', required=True, help='the x number')
    parser.add_argument('-y', '--y_nb', required=True, help='the y number')
    args = parser.parse_args()

    print('result is {} when {} multiplied by {}'.format(int(args.x_nb) * int(args.y_nb),
                                                         args.x_nb,
                                                         args.y_nb))

在我的主要 python 脚本中,我有:

#! /usr/bin/env python3

import subprocess
import concurrent.futures
import threading
...

args_list = []
for i in range(10):
    cmd = './test.py -x {} -y 2 '.format(i)
    args_list.append(cmd)

# just as an example, this line works fine
subprocess.run(args_list[0], shell=True)

# this multithreading is not working       
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
    executor.map(subprocess.run, args_list)

这里的问题是我无法将 shell=True 选项传递给 executor.map

我已经试过了没有成功:

args_list = []
for i in range(10):
    cmd = './test.py -x {} -y 2 '.format(i)
    args_list.append((cmd, eval('shell=True'))

args_list = []
for i in range(10):
    cmd = './test.py -x {} -y 2 '.format(i)
    args_list.append((cmd, 'shell=True'))

有人知道如何解决这个问题吗?

我认为 map 方法不能直接调用带有关键字参数的函数,但有 2 个简单的解决方案可以解决您的问题。

解决方案 1:使用 lambda 设置所需的额外关键字参数

lambda 基本上是一个调用您的真实函数并传递参数的小函数。如果关键字参数是固定的,这是一个很好的解决方案。

with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
    executor.map(lambda args: subprocess.run(args, shell=True), args_list)

方案二:使用executor.submit将函数提交给执行者

submit 方法允许您为目标函数指定参数和关键字参数。

with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
    for args in args_list:
        executor.submit(subprocess.run, args, shell=True)