使用参数和超时同时从另一个 .py 运行多个 .py

Posted

技术标签:

【中文标题】使用参数和超时同时从另一个 .py 运行多个 .py【英文标题】:Run multiple .py from another .py simultaneously with arguments and timeout 【发布时间】:2021-11-20 06:28:43 【问题描述】:

我有一个程序,比如说“main.py”,它通过参数“python main.py 3”或例如“python main.py 47”运行,这意味着在程序中运行特定的ID自己。

我正在尝试编写另一个脚本,比如说“start.py”,以便它启动一定数量的此类程序。如果在 start.py 中我写了线程 = 4,超时 = 5,那么它应该运行“python main.py 1”、“python main.py 2”、“python main.py 3”、“python main.py 4” " 同时执行,但每个命令之间有 5 秒的延迟。

我知道如何在一个线程中执行此操作,但在前一个线程完成之前不会运行其他参数。

threads = 4
id = 1
for i in range(threads):
    os.system(f"python main.py id")
    id += 1
    time.sleep(5)

我试图通过多处理来做到这一点,但我失败了。实现这一点的最佳方法是什么,我是否朝着正确的方向前进?

我已经通过 bash 完成了这项工作,但我只需要在 Python 中完成。

for ((i=1; i<=4; i++))
do
    python3 main.py "$i" &
done

【问题讨论】:

不要使用os.system() 来执行此操作。在main.py 内部确保有一个函数main() 接受参数。您可以在不对main.py 进行任何其他更改的情况下添加这样的功能。然后在start.pyimport main 并且每次你想启动那个功能时,做main.main(1) 等等。 【参考方案1】:

如果您不想或不能对 main.py 进行更改,那么您可以对当前代码进行的最简单更改就是在线程所以你不会阻塞:

from threading import Thread
import os
import time

def run_main(id):
    os.system(f"python main.py id")

threads = 4
id = 1
started_threads = []
for i in range(threads):
    if i != 0:
        time.sleep(5)
    t = Thread(target=run_main, args=(id,))
    t.start()
    started_threads.append(t)
    id += 1
for t in started_threads:
    t.join()

请注意,我已将呼叫转移到 time.sleep,因为您正在进行不需要的额外呼叫。

但这相当昂贵,因为每次调用main 都会启动一个 Python 解释器。如果我理解@BoarGules 提供的评论(尽管他的字面意思不会并行运行函数main 4 次而是按顺序运行),如果 main.py 是,则以下是替代实现结构如下:

import sys

def main(id):
    ... # process

if __name__ == '__main__':
    main(sys.argv[1])

然后你的 start.py,如果在 Linux 或使用 fork 启动新进程的某些平台下运行,编码如下:

from multiprocessing import Process
import os
import time
import main

threads = 4
id = 1
started_processes = []
for i in range(threads):
    if i != 0:
        time.sleep(5)
    p = Process(target=main.main, args=(id,))
    p.start()
    started_processes.append(p)
    id += 1
for p in started_processes:
    p.join()

但是如果你是在 Windows 或者一些使用 spawn 来启动新进程的平台下运行,那么你必须编写如下的 start.py 代码:

from multiprocessing import Process
import os
import time
import main

# required for Windows:
if __name__ == '__main__':
    threads = 4
    id = 1
    started_processes = []
    for i in range(threads):
        if i != 0:
            time.sleep(5)
        p = Process(target=main.main, args=(id,))
        p.start()
        started_processes.append(p)
        id += 1
    for p in started_processes:
        p.join()

而且您创建的每个新的 Process 实例最终都会运行一个新的 Python 解释器,因此与我提供的初始解决方案相比,您不会节省太多。

这就是为什么当您发布带有multiprocessing 标记的问题时,您还应该使用平台标记该问题。

【讨论】:

非常感谢您的详细解答!第一个代码完全解决了我所有的问题。当我决定继续前进时,我一定会考虑其余的代码。

以上是关于使用参数和超时同时从另一个 .py 运行多个 .py的主要内容,如果未能解决你的问题,请参考以下文章

从另一个脚本调用脚本的最佳方法是啥?

如何同时运行多个webdriver python程序?

Discord.py 如何从另一个文件运行代码?

如何运行 db:migrate 从另一个带参数的 rake 任务?

如何在火花中连接多个列,同时从另一个表中连接列名(每行不同)

如果 py.test 从另一个目录执行它,coverage.py 不会覆盖脚本