【问题标题】:What is the best way to create shared message stream for Python scripts?为 Python 脚本创建共享消息流的最佳方法是什么?
【发布时间】:2018-06-02 23:31:14
【问题描述】:

我想做的事:我需要一个简单的消息流,这样一些脚本可以在那里发送结果,而另一个脚本可以获取结果并异步执行一些工作。

主要问题:我想看看发生了什么,所以如果出现问题 - 我可以快速修复它。我尝试使用 Celery+RabbitMQ(可以看到带 args 的工人,使用 Flower,但调度太复杂)和 multiprocessing.Queue(简单,但看不到带 args 的工人)。


我做了什么:我尝试构建类似的东西,使用 MongoDB 封顶集合并使用多个进程运行 Popen,以做出反应。一些脚本将 smth 写入集合,下面的脚本会监视它,如果满足某些条件 - 运行另一个脚本。

主要问题: subprocess.Popen() 从 multiprocessing.Process() 内部的使用看起来不自然(仍然有效),所以我试图找到更好或更稳定的解决方案: )


监听脚本:

from pymongo import MongoClient, CursorType
from time import sleep
from datetime import datetime

from multiprocessing import Process
import subprocess

def worker_email(keyword):
     subprocess.Popen(["python", "worker_email.py", str(keyword)])

def worker_checker(keyword):
     subprocess.Popen(["python", "worker_checker.py", str(keyword)])

if __name__ == '__main__':

    #DB connect
    client = MongoClient('mongodb://localhost:27017/')
    db = client.admetric
    coll = db.my_collection
    cursor = coll.find(cursor_type = CursorType.TAILABLE_AWAIT)

    #Script start UTC time
    utc_run = datetime.utcnow()

    while cursor.alive:
        try:
            doc = cursor.next()
            #Print doc name/args to see in command line, while Listener runs
            print(doc)
            #Filter docs without 'created' data
            if 'created' in doc.keys():
                #Ignore docs older than script
                if doc['created'] > utc_run:
                    #Filter docs without 'type' data
                    if 'type' in doc.keys():
                        #Check type
                        if doc['type'] == 'send_email':
                            #Create process and run external script
                            p = Process(target=worker_email, args=(doc['message'],))
                            p.start()
                            p.join()
                        #Check type
                        elif doc['type'] == 'check_data':
                            #Create process and run external script
                            p = Process(target=worker_checker, args=(doc['message'],))
                            p.start()
                            p.join()
        except StopIteration:
            sleep(1)

【问题讨论】:

  • 为什么要使用subprocess 来运行 Python 脚本?只需通过multiprocessing.Process 运行 Python 代码。
  • @noxdafox 我在每个外部文件中都有 500-600 行代码,所以 subprocess 看起来比 from import * 更干净。我害怕破坏主脚本命名空间。

标签: python mongodb python-3.x subprocess multiprocessing


【解决方案1】:

只要您可以控制worker_emailworker_checker 逻辑,就不需要在单独的解释器中执行。

只需在两个模块中公开一个入口点并通过multiprocessing.Process 运行它们。

worker_email.py

def email_job(message):
    # start processing the message here

worker_checker.py

def check_job(message):
    # start checking the message here

listener_script.py

# you are not going to pollute the listener namespace
# as the only names you import are the entry points of the scripts
# therefore, encapsulation is preserved
from worker_email import email_job
from worker_checker import check_job

email_process = Process(target=email_job, args=[message])
check_process = Process(target=check_job, args=[message])

如果您无法从工作模块公开入口点,则只需运行 subprocess.Popen。将它们包装在 Process 中没有任何好处。

【讨论】:

  • 1.我尝试使用 import,但工作文件仍然包含 500-600 行代码和许多函数,所以我决定使用 Popen() 比 from import * 更干净 :) 是吗? --- 2. 将它们包装在一个进程中允许使用多个内核,我需要每 5-10 秒运行 50-100 个工作人员。
  • 1.不,它不干净。只导入你需要的函数比启动一个完全独立的 Python 解释器要好得多。检查我的代码示例中的注释。 2. subprocess.Popen 已经在新进程中运行逻辑。如果你将它包装在一个进程中,你最终会得到两个进程,其中一个正在等待另一个。没有任何好处:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-19
  • 1970-01-01
  • 2018-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-06
相关资源
最近更新 更多