Python请求在gevent greenlets之间共享Session对象,线程安全(在greenlets之间)?

时间:2014-05-29 14:00:03

标签: python python-2.7 thread-safety python-requests gevent

可以在gevented程序中安全地跨greenlet使用requests库会话对象吗?

编辑 - 添加更多解释:

当greenlet因为已经发出套接字调用将请求发送到服务器而产生时,另一个greenlet可以安全地使用同一个套接字(在共享会话对象内)发送自己的请求吗?

结束编辑

我尝试使用此处发布的代码({3}}对此进行测试 - 但是我没有错误或意外结果。但是,这不会验证线程安全性。

在测试中,我使用共享会话对象来发出大量请求,并尝试查看对象是否混淆了请求 - 这有点天真,但我没有任何例外。

为方便起见,我在这里重新粘贴代码:

client.py

import gevent
from gevent.monkey import patch_all
patch_all()

import requests
import json

s = requests.Session()

def make_request(s, d):
    r = s.post("http://127.0.0.1:5000", data=json.dumps({'value': d}))
    if r.content.strip() != str(d*2):
        print("Sent %s got %s" % (r.content, str(d*2)))
    if r.status_code != 200:
        print(r.status_code)
        print(r.content)

gevent.joinall([
    gevent.spawn(make_request, s, v)
    for v in range(300)
])

server.py

from gevent.wsgi import WSGIServer
from gevent.monkey import patch_all

patch_all()

from flask import Flask
from flask import request

import time
import json

app = Flask(__name__)

@app.route('/', methods=['POST', 'GET'])
def hello_world():
    d = json.loads(request.data)
    return str(d['value']*2)

if __name__ == '__main__':
    http_server = WSGIServer(('', 5000), app)
    http_server.serve_forever()

精确库版本:

requirements.txt

Flask==0.10.1
Jinja2==2.7.2
MarkupSafe==0.23
Werkzeug==0.9.4
argparse==1.2.1
gevent==1.0.1
greenlet==0.4.2
gunicorn==18.0
itsdangerous==0.24
requests==2.3.0
wsgiref==0.1.2

是否有其他测试可以检查greenlet线程的安全性?请求文档在这一点上不太清楚。

1 个答案:

答案 0 :(得分:7)

requests的作者还创建了一个gevent - 集成包:grequests。请改用它。

它支持使用session关键字传递会话:

import grequests

s = requests.Session()

requests = [grequests.post("http://127.0.0.1:5000", 
                           data=json.dumps({'value': d}), session=s)
            for d in range(300)]

responses = grequests.map(requests)
for r in responses:
    if r.content.strip() != str(d*2):
        print("Sent %s got %s" % (r.content, str(d*2)))
    if r.status_code != 200:
        print(r.status_code)
        print(r.content)