eventlet 之 monkeypatch 带来的若干兼容性问题实例分析

概述

最近需要在一个基于nameko/eventlet的服务中集成grpc client, 遇到了一个monkeypatch带来的兼容性问题, 测试代码如下:

import eventlet

eventlet.monkey_patch(thread=True)

import threading

from grpc._cython import cygrpc


class TestThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        completion_queue = cygrpc.CompletionQueue()
        while True:
            _ = completion_queue.poll()


threading._VERBOSE = True
t = TestThread()
t.start()

print('if thread is not patched, this message will be printed')

当对thread模块patch之后, 进程卡在了t.start(), 只有按ctrl+c中断该线程之后, 程序才继续运行. 但如果不对thread进行patch, 线程start之后, 程序继续运行. 这是为什么呢?

分析

使用pdb进行调试, 分为两种情况:

1. 对thread进行patch

clipboard.png
程序在switch之后切换到TestThread运行, 似乎就切换不回到主线程了!按下ctrl+c后TestThread才中断, 并在主线程继续运行.

2. 不对thread进行patch

在TestThread进入start之后, self.__started.wait()直接返回, 值得注意的是, 在start内部调用_start_new_thread就直接启动子线程, 并且直接返回了!
clipboard.png

结论

可见monkeypatch修改了threading标准库中的_start_new_thread方法, Condition类等. 当patch之后,_start_new_thread方法并不直接启动线程, 而是返回一个greenlet, 在这个问题当中, grpc调用的是一个c extension中的threading pool, monkeypatch无法对这个extension进行patch, 导致了后来switch到这个greenlet中时其实是进入到另一个线程中. 因为greenlet无法在不同的线程中切换, 导致程序无法从TestThread切回来, 只有主动去中断TestThread, 才能被恢复.
自从遇到了这个问题, 以后做项目的并发模型就更加慎重了:). 如果不清楚monkeypatch到底做了些什么, 在选择协程做python的底层并发模式时, 请三思.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值