前言:
python requests是个老牌的http client库,在多线程下(threading)是安全的,在协程下自然也是安全的。值得一说的是Requets自身并没有实现连接池,而是引入了标准库urllib2的连接池。池的线程安全实现很简单,就是加锁控制边界。
该文章后续仍在不断的更新修改中, 请移步到原文地址 http://xiaorui.cc/?p=6245
问题:
既然是requests是线程安全的,那么在多进程下是否安全? 是否安全需要看你如何去使用multiprocessing requests了。如果是先fork子进程再进行http请求,那么是没有问题的。如果是先使用了session连接池,再去fork子进程,那么会出现多进程下socket读写不安全的问题。
requests默认有一个session对象,该session对象会绑定一个连接池。当你在fork子进程前,先请求了一个api,那么产生的socket连接会保留在session对象里。这时候你fork了子进程,子进程不仅继承父进程空间,而且会继承文件描述符。当再次尝试请求http请求时,有可能出现多个进程对一个连接进行写入和读取。
// xiaorui.cc import time import requests from multiprocessing import Process, Queue uri = 'http://www.163.com' q = Queue() session = requests.Session() def req(args): while 1: response = session.get(uri) print(response) time.sleep(3) def feed(): q.put("sss") if __name__ == '__main__': response = session.get(uri) pids = [] for num in range(5): p = Process(target=req, args=(11, )) p.start() pids.append(p) for pid in pids: pid.join()
我们会发现不同pid的进程往同一个文件描述符去读写数据,这个就是requests session非进程安全的表现了。
如何解决?
python多进程下不要共用同一个requests session,或者说不要共用一个存有连接对象的session对象。
个人觉得python那么多网络库的连接池安全方面,redis-py做的就很好,redis py会通过pid来判断连接池对象是否从父进程继承的,如是继承则重新实例化新的连接池对象。
总结:
到此为止,python requests session的进程安全问题已经描述完毕。