python requests是个老牌的http client库,在多线程下(threading)是安全的,在协程下自然也是安全的。值得一说的是Requets自身并没有实现连接池,而是引入了标准库urllib2的连接池。池的线程安全实现很简单,就是加锁控制边界。 既然是requests是线程安全的,那么在多进程下是否安全? 是否安全需要看你如何去使用multiprocessing requests了。如果是先fork子进程再进行http请求,那么是没有问题的。如果是先使用了session连接池,再去fork子进程,那么会出现多进程下socket读写不安全的问题。
requests默认有一个session对象,该session对象会绑定一个连接池。当你在fork子进程前,先请求了一个api,那么产生的socket连接会保留在session对象里。这时候你fork了子进程,子进程不仅继承父进程空间,而且会继承文件描述符。当再次尝试请求http请求时,有可能出现多个进程对一个连接进行写入和读取。
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来判断连接池对象是否从父进程继承的,如是继承则重新实例化新的连接池对象。