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
smelond
V2EX  ›  Python

Python 关于多线程和多进程同时共用问题

  •  
  •   smelond · 2019-01-06 17:57:07 +08:00 · 4841 次点击
    这是一个创建于 2137 天前的主题,其中的信息可能已经有所发展或是发生改变。

    下面这段代码在 windows 下运行就报错 NameError: name 'SEM' is not defined

    在 windows7 windows10 测试 报错

    在 Mac Linux 下测试 能正常运行

    如果我在代码的最上面给 SEM 和 TIME_OUT 赋值后,就能正常运行

    但是我需要用户加参数将值带进去,而不是事先定义好,所以只能放到 argparse 里面。我现在很疑惑,这个问题能解决吗?

    时间过了两天了,依旧没有解决这个问题,希望小伙伴们能和我一起讨论一下怎么回事,谢谢!

    # /usr/bin/env python
    # _*_ coding:utf-8 _*_
    
    
    import argparse, datetime, time
    import threading
    from multiprocessing import Pool
    
    
    def test(i):
        with SEM:
            print(i)
            time.sleep(TIME_OUT)
    
    
    def test1(c):
        threads = []
        for i in range(int(200)):
            t = threading.Thread(target=test, args=(i,))
            t.start()
            threads.append(t)
        for t in threads:
            t.join()
    
    
    def main():
        start_time = time.time()
        print(datetime.datetime.now().strftime('Start Time: %m/%d/%Y %H:%M:%S'))
        p = Pool(int(args.PROCESS))
        for i in range(10):
            p.apply_async(test1, args=(i,))
        p.close()
        p.join()
        print(datetime.datetime.now().strftime('Complete time: %m/%d/%Y %H:%M:%S'))
        print("Total time:%s" % (time.time() - start_time))
    
    
    if __name__ == '__main__':
        parser = argparse.ArgumentParser(description='test')
        parser.add_argument('-m', dest='PROCESS', type=int, help='多进程数量,默认 5', default=5)
        parser.add_argument('-t', dest='THREAD', type=int, help='多线程数量,默认 20', default=20)
        parser.add_argument('-o', dest='OVERTIME', type=int, help='超时时间 默认 2', default=2)
        args = parser.parse_args()
        SEM = threading.Semaphore(int(args.THREAD))
        TIME_OUT = int(args.OVERTIME)
        main()
    
    
    22 条回复    2019-01-10 11:10:52 +08:00
    ysc3839
        1
    ysc3839  
       2019-01-06 18:07:25 +08:00 via Android
    Windows 不支持 fork 吧?没把变量拷贝到别的进程。
    smelond
        2
    smelond  
    OP
       2019-01-06 18:26:06 +08:00
    @ysc3839 请问这个还有办法解决吗
    ysc3839
        3
    ysc3839  
       2019-01-06 18:29:04 +08:00 via Android   ❤️ 1
    @smelond 在 test1 中初始化 SEM。
    smelond
        4
    smelond  
    OP
       2019-01-06 18:37:39 +08:00
    @ysc3839 咋个初始化呢,是这样么? 但是这样之后程序一秒运行完成,没有执行里面的操作
    ``` python

    global SEM
    SEM = threading.Semaphore(int(args.THREAD))
    ```
    ysc3839
        5
    ysc3839  
       2019-01-06 18:43:52 +08:00 via Android
    @smelond 那我也不知道了……是我不懂 Python。
    lihongjie0209
        6
    lihongjie0209  
       2019-01-06 18:58:07 +08:00
    你要把这两个变量放到全局变量中去
    smelond
        7
    smelond  
    OP
       2019-01-06 19:04:51 +08:00
    @ysc3839 不好意思,感谢你的回复,感觉可能惹你生气了,我对 Python 也不是太熟练,听到你说了在 test1 里面初始化 SEM,我想了一下,想到了我可以先将:
    sem = int(args.THREAD)
    time_out = int(args.OVERTIME)
    放到 main 函数里面,然后通过传参方式,从 mian-> test1->test 最后直接在 test 里面写入
    with threading.Semaphore(sem): 然后可以成功的运行,感谢你的回复
    smelond
        8
    smelond  
    OP
       2019-01-06 19:07:00 +08:00
    @lihongjie0209 放到全局变量里面 不管怎么样,test 函数就是不识别
    ysc3839
        9
    ysc3839  
       2019-01-06 19:56:52 +08:00 via Android
    @smelond 我没生气啊,我真的不懂啊……
    我从来没用过 multiprocess,前面只是随口说说以为可以解决问题,但解决不了我就真的不懂了。
    Vegetable
        11
    Vegetable  
       2019-01-06 20:49:17 +08:00 via Android
    一般来说,可以认为 Windows 不能直接使用 multiprocessing,也就是不支持多进程。
    JCZ2MkKb5S8ZX9pq
        12
    JCZ2MkKb5S8ZX9pq  
       2019-01-06 20:58:24 +08:00
    多进程好像可以设一个 value 作为公用的变量,类似锁吧。
    多线程以前试过,但没什么印象了。反正最后用多进程了。
    xiangace
        13
    xiangace  
       2019-01-07 01:08:18 +08:00
    1. 多线程实际上还是利用单核, 直接用多进程.
    2. Python 在共享全局变量这块做的不太好, 多线程场景可以查询下 thread local 相关的资料.
    多进程考虑 multiprocessing 的 value 机制, multiprocessing 支持一个 daemon 进程维护这组变量, 多进程通过 IPC
    xiangace
        14
    xiangace  
       2019-01-07 01:14:33 +08:00
    接上一跳评论,理解错题意了, win 下的机制比较诡异.
    lrxiao
        15
    lrxiao  
       2019-01-07 01:14:34 +08:00
    multi process 本身就不能假设同一个东西会 share between processes...
    然后就是 message-passing or shared memory
    https://docs.python.org/2/library/multiprocessing.html#multiprocessing.Value
    a226679594
        16
    a226679594  
       2019-01-07 08:33:10 +08:00
    把这两个变量放到全局变量中去
    arrow8899
        17
    arrow8899  
       2019-01-07 09:13:13 +08:00
    多进程是不能共享变量的,可以用共享内存试试
    arrow8899
        18
    arrow8899  
       2019-01-07 09:24:36 +08:00   ❤️ 1
    shared_mem = manager.dict() 这一句就是添加一个共享内存,可以在多进程之间使用
    ```
    # /usr/bin/env python
    # _*_ coding:utf-8 _*_


    import argparse, datetime, time
    import threading
    import multiprocessing


    def test(i):
    with SEM:
    print(i)
    time.sleep(TIME_OUT)


    def test1(c, data):
    global SEM
    global TIME_OUT
    SEM = data['SEM']
    TIME_OUT = datda['TIME_OUT']

    threads = []
    for i in range(200):
    t = threading.Thread(target=test, args=(i,))
    t.start()
    threads.append(t)
    for t in threads:
    t.join()


    def main(args):
    start_time = time.time()
    print(datetime.datetime.now().strftime('Start Time: %m/%d/%Y %H:%M:%S'))
    manager = multiprocessing.Manager()
    p = multiprocessing.Pool(int(args.PROCESS))

    shared_mem = manager.dict()
    shared_mem['SEM'] = threading.Semaphore(int(args.THREAD))
    shared_mem['TIME_OUT'] = int(args.OVERTIME)

    for i in range(10):
    p.apply_async(test1, args=(i, shared_mem))
    p.close()
    p.join()
    print(datetime.datetime.now().strftime('Complete time: %m/%d/%Y %H:%M:%S'))
    print("Total time:%s" % (time.time() - start_time))


    if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='test')
    parser.add_argument('-m', dest='PROCESS', type=int, help='多进程数量,默认 5', default=5)
    parser.add_argument('-t', dest='THREAD', type=int, help='多线程数量,默认 20', default=20)
    parser.add_argument('-o', dest='OVERTIME', type=int, help='超时时间 默认 2', default=2)
    main(parser.parse_args())
    ```
    julyclyde
        19
    julyclyde  
       2019-01-07 10:08:34 +08:00
    在函数里引用了
    既不是参数,又不是本地定义
    的变量
    这是一种很典型的错误
    qcts33
        20
    qcts33  
       2019-01-07 11:07:31 +08:00
    显试的传递一下不行吗……
    a226679594
        21
    a226679594  
       2019-01-09 09:22:51 +08:00
    一般来说,可以认为 Windows 不能直接使用 multiprocessing,也就是不支持多进程。
    old18
        22
    old18  
       2019-01-10 11:10:52 +08:00
    多进程不共享全局变量, 把 SEM 存放在消息队列里,就应该好了...
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5328 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 07:16 · PVG 15:16 · LAX 23:16 · JFK 02:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.