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
4ever911
V2EX  ›  Python

Python Thread/gevent 等待 Event 完成,主线程被锁

  •  
  •   4ever911 · 2016-10-04 16:31:56 +08:00 · 3072 次点击
    这是一个创建于 3007 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我的程序需要调用一个第三方 C++ 写的函数 Func_from_CPP() 这个函数用了一个 WaitForSingleObject 函数,大概要处理 3 到 5 秒才能处理完成返回, 所以导致我的 UI 会被 block 掉。

    所以我就想把这个函数丢到 Thread 或者 Gevent 里面去处理,等处理完成再异步通知我去对返回数据处理。

    但是,奇怪的是,不管我用 thread 还是 gevent , UI 始终都是被 block 掉,都需要等函数处理完成才能返回。

    是不是因为 Python 本身对线程的支持不够,导致对于 WaitForSingleObj 这样的函数,不管是否使用工作线程 /协程序,它始终是会让主线程处于等待状态?


    大致代码如下:

    CPP
    ————————————————————————————
    result Func_from_CPP()
    {
    waitforsomeevent() //WaitForSingleObject
    dowork()
    return reuslt
    }


    python
    ————————————————————————————
    def Work(self):
    Func_from_CPP()


    def onbutt onClicked(self):
    Work() //直接掉用,函数调用这几秒 UI 会挂掉

    threading.thread(self.Work)
    threading.start() //尝试用线程来做, UI 仍然挂掉

    gevent.spawn(self.Work)
    gevent.sleep(0) // 第三次尝试 gevent UI 仍然挂掉



    是我打开姿势不对吗?
    12 条回复    2016-10-05 19:46:19 +08:00
    mooncakejs
        1
    mooncakejs  
       2016-10-04 18:15:06 +08:00 via iPhone
    我猜是 gil
    alqaz
        2
    alqaz  
       2016-10-04 19:03:07 +08:00
    应该是楼上说的原因,而且 Func_from_CPP 这个函数调用了 WaitForSingleObject 函数,这是一个同步操作。 If the object's state is nonsignaled, the calling thread enters the wait state until the object is signaled or the time-out interval elapses.所以,改写这个 c++库?
    Zzzzzzzzz
        3
    Zzzzzzzzz  
       2016-10-04 19:25:48 +08:00
    第三种只适用于 IO 堵塞, 并且 C/C++层有暴露相应的 fd 的接口可以加到 gevent 的 ioloop 里.
    第二种倒是通用, 但前提是拿 C 或者 Cython 嵌一层释放 GIL 的包装.
    wangxn
        4
    wangxn  
       2016-10-04 19:34:14 +08:00 via Android
    在 Func_from_CPP() 里面使用原生线程才行。如 std::thread 什么的。
    4ever911
        5
    4ever911  
    OP
       2016-10-04 20:13:47 +08:00 via iPhone
    现在问题是我不可能去修改那部分 cpp 代码
    alqaz
        6
    alqaz  
       2016-10-04 22:24:51 +08:00
    @4ever911 封装一层试下,实在不行,就两层。
    ericls
        7
    ericls  
       2016-10-04 22:27:19 +08:00 via iPhone
    可以用 asyncio.run_in_executor 试一下 需要用 processpoolexecuror
    zhuangzhuang1988
        8
    zhuangzhuang1988  
       2016-10-04 23:20:21 +08:00 via iPad
    因为没有释放 Gil
    zhuangzhuang1988
        9
    zhuangzhuang1988  
       2016-10-04 23:25:11 +08:00 via iPad
    推荐看 time.sleep 的 c 实现就知道了。。
    binux
        10
    binux  
       2016-10-04 23:30:00 +08:00
    丢进程里处理就完了呗。
    4ever911
        11
    4ever911  
    OP
       2016-10-05 14:58:06 +08:00 via iPad
    @binux 丢给进程处理,也要在 thread.join() 等待完成吧。还是会 block 掉主线程吧,我回头试试看。
    ryd994
        12
    ryd994  
       2016-10-05 19:46:19 +08:00 via Android
    @4ever911 先不 join ,用 pipe ,这样就是 IO 问题,用线程还是 gevent 都可以
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2821 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 13:27 · PVG 21:27 · LAX 05:27 · JFK 08:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.