2015-01-11 90 views
5

首先,抱歉我的英语不好。 在我的项目中,我有很多I/O网络请求。主要数据存储在另一个项目中,访问由Web API(JSON/XML)提供,轮询。我们为每个新用户会话使用此API(获取有关用户的信息)。有时,我们在等待回应时遇到问题。 我们使用nginx + uwsgi + django。如你所知,Django是同步的(或阻塞)。 我们使用uwsgi和多线程来解决网络IO等待的问题。 我决定读一下gevent。我理解合作与抢先式多任务之间的区别。我希望gevent是更好的解决方案,然后uwsgi线程解决此问题(网络I/O瓶颈)。但结果几乎相同。有时候,gevent较弱。 也许某处我错了。请告诉我。Uwsgi与gevent vs线程

这里是uwsgi配置示例。 GEVENT:

$ uwsgi --http :8001 --module ugtest.wsgi --gevent 40 --gevent-monkey-patch 

线程:

$ uwsgi --http :8001 --module ugtest.wsgi --enable-threads --threads 40 

控制器例如:

def simple_test_action(request): 
    # get data from API without parsing (only for simple I/O test) 
    data = _get_data_by_url(API_URL) 
    return JsonResponse(data, safe=False) 

import httplib 
from urlparse import urlparse 
def _get_data_by_url(url): 
    u = urlparse(url) 
    if str(u.scheme).strip().lower() == 'https': 
     conn = httplib.HTTPSConnection(u.netloc) 
    else: 
     conn = httplib.HTTPConnection(u.netloc) 
    path_with_params = '%s?%s' % (u.path, u.query,) 
    conn.request("GET", path_with_params) 
    resp = conn.getresponse() 
    print resp.status, resp.reason 
    body = resp.read() 
    return body 

测试(与geventhttpclient):

def get_info(i): 
    url = URL('http://localhost:8001/simpletestaction/') 
    http = HTTPClient.from_url(url, concurrency=100, connection_timeout=60, network_timeout=60) 
    try: 
     response = http.get(url.request_uri) 
     s = response.status_code 
     body = response.read() 
    finally: 
     http.close() 


dt_start = dt.now() 
print 'Start: %s' % dt_start 

threads = [gevent.spawn(get_info, i) for i in xrange(401)] 
gevent.joinall(threads) 
dt_end = dt.now() 

print 'End: %s' % dt_end 
print dt_end-dt_start 

在这两种情况下,我都有类似的时间。在类似的问题(API代理)中,gevent/greenlets和协作式多任务的优点是什么?

回答

5

并发40并不是让gevent闪耀的水平。 Gevent是关于并发性而不是并行性(或每请求性能),因此具有这种“低”的并发性水平并不是获得改进的好方法。

通常你会看到GEVENT并发有成千上万的水平,而不是40 :)

对于阻塞I/O蟒蛇线程不坏(GIL的期间I/O发布),GEVENT的优势在资源使用方面(有1000条python线程会过度杀伤),并且不需要考虑锁定和朋友。

很明显,请记住,您的整个应用程序必须对gevent友好以获得优势,而django(默认情况下)需要一点调整(因为必须更改gevent友好的示例数据库适配器)。

+0

我想用另一个线程/ greenlets来测试它。不是数千,而是数百。和结果类似。 我认为如果我的控制器操作中有多个请求(使用join()/ joinall()),gevent是最好的选择。 但在我的问题(“代理”-API)我没有显着的好处。 在第一种情况下(线程)我们有一个简单的配置:-threads N. 在第二种情况下(gevent),我们在修补postgres驱动程序(例如),redis等时遇到了很多问题。另外,一个完整的堆栈跟踪的问题... – OLMER

+0

对不起,不知道跟着你,如果你不能“补丁”django,你不能使用gevent,那就是。你的应用程序必须是100%非阻塞的,否则它是一个阻止应用程序,gevent不会帮助你(好吧,它甚至会做得最差) – roberto

1

服务非阻塞不是关于性能,而是关于并发性。如果请求时间的99%用于子请求中,则不能只优化这99%。但是,当所有可用线程忙于服务时,新客户端将被拒绝,尽管99%的线程时间用于等待子请求完成。非阻塞服务允许您通过在不受可用线程数量限制的“处理程序”之间共享该空闲时间来利用该空闲时间。因此,如果99%正在等待,那么另外1%是CPU限制的处理,因此在最大化CPU之前可以同时拥有100倍以上的连接数 - 而不需要100倍以上的线程,这可能太昂贵(并且使用Python的GIL问题,你必须使用更昂贵的子流程)。

现在,正如roberto所说,你的代码必须是100%非阻塞才能挽救空闲时间。但是,从上面的百分比示例中可以看出,只有在请求几乎完全IO限制时才会变得非常重要。如果是这种情况,那么很可能你不需要Django,至少对于你的应用程序的那部分来说。