开发环境: python 2.7.x requests gevent 并发编程
在并发编程的开发过程中,我们常会在导入socket模块前使用gevent.monkey.patch_all(),以将涉及socket模块的IO设置为非阻塞。
那么问题来了,当requests 遇到 gevent.monkey.patch_all(), 你可以也会遇到这样的异常信息:
TypeError: wrap_socket() got an unexpected keyword argument 'server_hostname'
或者是:
TypeError: __init__() got an unexpected keyword argument 'check_hostname'
当对问题进行深入探究发现, requests是基于urllib3实现的, 此模块中的ssl_.py 使用server_hostname作为参数调用wrap_socket。然后当此方式遇到gevent 中的monkey patched 方式就会出现异常。
查资料发现原因好像是因为SNI相关功能向2.7系列的后退,导致urllib将python 2.7.8+视为python 3.2+而导致的。
我这里的解决方案有三个:
- 查看gevent 版本,如果为1.0.2或者更低版本,那么通过升级为更高版本可以避免此异常;
- requests 文档中说明如果异步调用,可以使用更高级的模块 grequests,使用此模块进行请求也可以避免此异常,但弊端是此方式需要修改代码的工作量可能比较大;
- 通过grequests此模块的源码,发现模块中的实现原理是在gevent.monkey.patch_all()中传入了参数thread=False, select=False, 以避免对threading和select模块的补丁。所以我们在原代码中可以借鉴,直接传入这两个参数,也可以避免此异常;