V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
eccentric579
V2EX  ›  Python

[求助提问] subprocess 的并行的一个问题

  •  
  •   eccentric579 · 174 天前 · 1501 次点击
    这是一个创建于 174 天前的主题,其中的信息可能已经有所发展或是发生改变。
    class test(object):
        def __init__(self) -> None:
            self.p = None
            self.data = None
        def request(self):
            self.p = subprocess.Popen(['pwsh' ,'-Command' ,'ping', '127.0.0.1'], stdout=subprocess.PIPE, encoding='gbk')
        def process(self):
            self.data = self.p.communicate()[0]
    
    if __name__ == "__main__":
        l = [test()] * 5
        for i in l:
            i.request()
        for i in l:
            i.process()
    
    • 为了能够并行(应该是并行吧),所以把 Popen 构造函数和 communicate()放在两个类方法里
    • 这样似乎导致了 communicate 的时候子进程已经终止,PIPE 关闭了( I/O operation on closed file.)读不到 stdout
    • 有什么办法可以弥补么?或者应该换一种写法?
    • 大概有 500 个 test 对象
    第 1 条附言  ·  174 天前
    • 如果不用类的写法,把两个类方法直接放到对应的两个循环里一点问题都没有
    第 2 条附言  ·  174 天前
    def request():
        return subprocess.Popen(['pwsh' ,'-Command' ,'ping', '127.0.0.1'], stdout=subprocess.PIPE, encoding='gbk')
    def process(p):
        p.communicate()[0]
    
    if __name__ == "__main__":
        pool= []
        for _ in range(5):
            pool.append(request())
        for p in pool:
            process(p)
    
    • 这样是并行的,也不会报错
    • 为什么经过了类,PIPE就关闭了
    8 条回复    2022-04-13 00:35:48 +08:00
    lolizeppelin
        1
    lolizeppelin  
       174 天前
    subprocess 不长建议你好好读一下,本质上都会用到系统函数进行父子进程互交,win/linux 还不一样。
    ppj
        2
    ppj  
       174 天前
    建议加数据 data 的获取和 p 放在 request 里,数据处理放在 process 里。
    eccentric579
        3
    eccentric579  
    OP
       174 天前
    @ppj data 是用 communicate()阻塞获取的,放在一起不能并行
    SenLief
        4
    SenLief  
       174 天前
    为什么是构造 test 类,这并行的是把那个 pwsh 运行 500 次吗?
    ec0
        5
    ec0  
       174 天前   ❤️ 1
    [test()] * 5 相当于
    t = test()
    [t, t, t, t, t] 也就是说 list 里的是同一个 t ,对同一个 t 多次调用 communication 自然会报错

    改成 [test() for i in range(5)] 这样生成的才是 5 个不一样的对象
    imycc
        6
    imycc  
       174 天前   ❤️ 1
    [test()] * 5 有问题,都是同一个实例

    (假设你要 ping 的地址是实例化的参数,那更容易理解 [test(ip)] *5 这样错在哪里了
    eccentric579
        7
    eccentric579  
    OP
       174 天前
    @ec0 万分感谢,我自己一天都不一定能想到这里出错了
    eccentric579
        8
    eccentric579  
    OP
       174 天前
    @SenLief
    只是为了测试并行,所以没有给对象初始化赋值

    @imycc
    是啊是啊,只是想偷个懒的,结果把自己绕进去了
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2232 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 584ms · UTC 14:30 · PVG 22:30 · LAX 07:30 · JFK 10:30
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.