【问题标题】:Running multiple independent python scripts concurrently同时运行多个独立的python脚本
【发布时间】:2017-11-28 18:44:48
【问题描述】:

我的目标是创建一个主要的 python 脚本,在 windows server 2012 中同时执行多个独立的 python 脚本。我认为的好处之一是我可以将 taskscheduler 指向一个 main.py 脚本,而不是多个 .py 脚本。我的服务器有 1 个 CPU。我已经阅读了multiprocessingthreadsubprocess,这只会增加我的困惑。在美国东部标准时间 9:30 开市后,我基本上同时为不同的股票代码运行多个交易脚本。以下是我的尝试,但我不知道这是否正确。非常感谢任何方向/反馈!

import subprocess

subprocess.Popen(["python", '1.py'])
subprocess.Popen(["python", '2.py'])
subprocess.Popen(["python", '3.py'])
subprocess.Popen(["python", '4.py'])

【问题讨论】:

  • 尝试使用队列,例如 sqs
  • 我喜欢 Python —— 但这可能是 bash 更适合你的工具之一:stackoverflow.com/questions/28549641/…
  • python 脚本是否以某种方式相关或完全不相关?如果有,是什么关系?
  • 重击?在 Windows Server 2012 上?
  • @SteveJ bash -> 批处理。 START "" "path-to-python" "path-to-script" 几乎可以实现相同的效果

标签: python multithreading subprocess multiprocessing


【解决方案1】:

我想我会尝试这样做:

from multiprocessing import Pool

def do_stuff_with_stock_symbol(symbol):
    return _call_api()

if __name__ == '__main__':
    symbols = ["GOOG", "APPL", "TSLA"]
    p = Pool(len(symbols))
    results = p.map(do_stuff_with_stock_symbol, symbols)
    print(results)

(多处理介绍中的修改示例:https://docs.python.org/3/library/multiprocessing.html#introduction

如果您处理大量股票代码,请考虑使用恒定的池大小,因为每个 python 进程都会使用一些内存。

另外,请注意,如果您正在处理 I/O 绑定的工作负载(调用 API、从磁盘写入和读取),使用线程可能会好很多。在处理计算绑定工作负载时,python 确实需要进程(因为全局解释器锁)。

使用线程和并发期货库的示例如下:

import concurrent.futures

TIMEOUT = 60

def do_stuff_with_stock_symbol(symbol):
    return _call_api()

if __name__ == '__main__':
    symbols = ["GOOG", "APPL", "TSLA"]

    with concurrent.futures.ThreadPoolExecutor(max_workers=len(symbols)) as executor:
        results = {executor.submit(do_stuff_with_stock_symbol, symbol, TIMEOUT): symbol for symbol in symbols}

        for future in concurrent.futures.as_completed(results):
            symbol = results[future]
            try:
                data = future.result()
            except Exception as exc:
                print('{} generated an exception: {}'.format(symbol, exc))
            else:
                print('stock symbol: {}, result: {}'.format(symbol, data))

(修改示例来自:https://docs.python.org/3/library/concurrent.futures.html#threadpoolexecutor-example

请注意,线程仍会使用一些内存,但比进程少。

如果您想将每个股票代码的内存消耗降至最低,您可以使用 asyncio 或绿色线程,但在某些时候您会因为所有并发 API 调用而遇到网络带宽问题 :)

【讨论】:

  • 哇,这可能是比我想象的解决方案更好的方法。那么我是否将所有常规代码放在 do_stuff_with_stock_symbol(symbol) 方法中的 return 调用之后?知道如何使用线程执行确切的操作,因为我的服务器中只有 1GB 内存。
  • 而不是返回_call_api(),您可以(可能几乎)做任何您想做的事情。我添加了一个线程示例。
  • 感谢您的回答!您是否推荐线程示例,因为您很清楚我正在尝试做什么,即在美国东部标准时间 9:30 开市后同时为不同的交易品种运行多个交易脚本?
  • 不确定我是否有足够的信息来推荐任何东西,但对于 I/O 绑定的工作负载,线程和异步比进程 IMO 更有意义。如果这对您有帮助,请将我的回答标记为已接受:)
  • @gibbz00 换句话说:如果您不尝试调用 API AND 计算数千个素数,请使用线程或 asyncio! :)
【解决方案2】:

虽然您所问的可能不是处理您正在做的事情的最佳方式,但我过去也想做类似的事情,但花了一段时间才找到我需要的东西,所以回答您的问题:

我不保证这是“最好”的方法,但它在我的用例中有效。

我创建了一个我想用来扩展线程的类。

thread.py

"""
Extends threading.Thread giving access to a Thread object which will accept
A thread_id, thread name, and a function at the time of instantiation. The
function will be called when the threads start() method is called.
"""

import threading


class Thread(threading.Thread):
    def __init__(self, thread_id, name, func):
        threading.Thread.__init__(self)
        self.threadID = thread_id
        self.name = name

        # the function that should be run in the thread.
        self.func = func

    def run(self):
        return self.func()

我需要完成一些属于另一个包的工作

work_module.py

import...

def func_that_does_work():
    # do some work
    pass

def more_work():
    # do some work
    pass

然后是我想运行的主脚本 main.py

from thread import Thread
import work_module as wm


mythreads = []
mythreads.append(Thread(1, "a_name", wm.func_that_does_work))
mythreads.append(Thread(2, "another_name", wm.more_work))

for t in mythreads:
    t.start()

当 run() 返回时线程死亡。由于这是从线程扩展线程,因此这里的文档中有几个选项可用:https://docs.python.org/3/library/threading.html

【讨论】:

    【解决方案3】:

    如果您只想自动启动启动,那么创建一个 .bat 文件是尝试使用另一个 python 脚本执行此操作的绝佳而简单的替代方法。

    cmets 中链接的示例显示了如何在基于 unix 的机器上使用 bash 来执行此操作,但批处理文件可以使用 START 命令执行非常相似的操作:

    start_py.bat:

    START "" /B "path\to\python.exe" "path\to\script_1.py"
    START "" /B "path\to\python.exe" "path\to\script_2.py"
    START "" /B "path\to\python.exe" "path\to\script_3.py"
    

    START 的完整语法可以在here 中找到。

    【讨论】:

      猜你喜欢
      • 2021-06-06
      • 1970-01-01
      • 1970-01-01
      • 2022-06-09
      • 1970-01-01
      • 2019-01-19
      相关资源
      最近更新 更多