首页 > 解决方案 > Python2:在子进程中暂停或使用yield,并从另一个进程中获取值

问题描述

我正在使用 python3 编写一个程序(假设main.py下面在 python3 中运行)并利用现有的 python 扩展(用 c 编写,用 python2 编译),我没有源代码。可以说这个FrozenModule类来自这个扩展。它确实做了很多事情,但只是试图在这里简化它。基本上我可以订阅它的事件,我真的只是控制回调函数。这意味着我可以通过更新回调函数来改变流程。

问题是我必须重新组织流程,并且每次调用回调函数时都想冻结/暂停。

我想要的最终结果是:

1:a,i,x
5:b,j,y
8:c,k,z

这是目前我在这里得到的,下面的代码。但它并没有真正按照我想要的方式工作。我添加了set_trace只是为了检查流程。我得到正确输出的原因是因为我已经在和SELECTED中定义了值。实际上我希望这个来自func2.pyfunc3.pyfunc1.py

简而言之,我真的很想func1.py先运行,从中获取特定的键,然后运行func2.py,它基本上会遍历它拥有的数据,直到它遇到那个事件/键,然后执行回调。暂停,对 做同样的事情func3.py,然后也暂停。然后回到func1.py并重新做一遍。

目前它的工作方式(不是下面的代码,而是我正在重写的当前程序),它func1.py首先运行整个,然后键都是已知的,然后传递给func2.py然后func3.py我们分别获取值。最后,将其全部附加在一起以生成整个表,例如:

1:a,i,x
5:b,j,y
8:c,k,z

主要问题是这些工作非常大,可能需要很长时间。这也可能在中间崩溃,你的用户没有得到任何回报。所以新方法是逐行或逐行生成最终输出。而不是每列执行列,然后组合所有内容并将整个结果提供给用户。

下面代码的问题是,当我运行子进程时(我使用子进程的原因是因为扩展只需要在 python2 中),它真的会立即运行/迭代整个数据。我添加了对文件的写入只是为了确保发生这种情况。因此,只要您运行main.py,甚至无需点击'c'继续 set_trace,f2.txt就已经拥有:

1,i
5,j
8,k

它最初应该是空的,然后当我'c'进入 main 时,它应该只写 1 行,暂停,然后等待下一行。当然 set_trace 和写入文件只是为了测试。

简而言之,主要目标是逐行写入输出。两个主要问题是:1)每次调用回调时如何暂停子流程。2) 传递从func1.pyto获得的值func2.pyfunc3.py然后继续/取消暂停该过程。

对不起,很长的帖子。另外,我希望我的问题很清楚。

示例代码如下:

在 main.py

import subprocess


class ProcReader():
    def __init__(self, python_file):
        self.proc = subprocess.Popen(['python2', python_file], stdout=subprocess.PIPE)

    def __iter__(self):
        return self

    def __next__(self):
        while True:
            line = self.proc.stdout.readline()
            if not line:
                raise StopIteration
            return line


r1 = ProcReader("func1.py")
r2 = ProcReader("func2.py")
r3 = ProcReader("func3.py")


for l1, l2, l3 in zip(r1, r2, r3):
    d1 = l1.decode('utf-8').strip().split(",")
    d2 = l2.decode('utf-8').strip().split(",")
    d3 = l3.decode('utf-8').strip().split(",")
    print(f"{d1[0]}:{d1[1]},{d2[1]},{d3[1]}")
    import pdb
    pdb.set_trace()

在 func1.py

from frozenmodule import FrozenModule

def callback(k, v):
    with open("f1.txt", 'a') as f:
        print(f"{k},{v}")
        f.write(f"{k},{v}\n")
        fm.match = next(iter_items, None)
        # somehow pause here, maybe use yield?


SELECTED = [1, 5, 8]
FAKE_DATA = {1: 'a',
             5: 'b',
             8: 'c'}
iter_items = iter(SELECTED)
fm = FrozenModule(FAKE_DATA, callback)
fm.match = next(iter_items, None)
fm.run()

在 func2.py

from frozenmodule import FrozenModule

def callback(k, v):
    with open("f2.txt", 'a') as f:
        print(f"{k},{v}")
        f.write(f"{k},{v}\n")
        # somehow pause here, maybe use yield?
        # then get value from func1.py and set to fm.match
        fm.match = next(iter_items, None)



SELECTED = [1, 5, 8]
FAKE_DATA = {1: 'i',
             5: 'j',
             8: 'k'}
iter_items = iter(SELECTED)
fm = FrozenModule(FAKE_DATA, callback)
fm.match = next(iter_items, None)
fm.run()

在 func3.py

from frozenmodule import FrozenModule

def callback(k, v):
    with open("f3.txt", 'a') as f:
        print(f"{k},{v}")
        f.write(f"{k},{v}\n")
        # somehow pause here, maybe use yield?
        # then get value from func1.py and set to fm.match
        fm.match = next(iter_items, None)
        


SELECTED = [1, 5, 8]
FAKE_DATA = {1: 'x',
             5: 'y',
             8: 'z'}
iter_items = iter(SELECTED)
fm = FrozenModule(FAKE_DATA, callback)
fm.match = next(iter_items, None)
fm.run()

在frozenmodule.py

class FrozenModule():
    def __init__(self, fake_data, callback):
        self.fake_data = fake_data
        self.match = 0
        self.callback = callback

    def run(self):
        for x in range(10):
            if x == self.match:
                self.callback(x, self.fake_data[x])

标签: pythonsubprocessgenerator

解决方案


推荐阅读