2015-01-11 22 views
5

Trước hết, xin lỗi vì tiếng Anh xấu của tôi. Trong dự án của tôi, tôi có rất nhiều yêu cầu mạng I/O. Dữ liệu chính được lưu trữ trong một dự án khác và quyền truy cập được cung cấp bởi API web (JSON/XML), bỏ phiếu. Chúng tôi sử dụng API này cho mỗi phiên người dùng mới (nhận thông tin về người dùng). Và đôi khi, chúng tôi gặp sự cố khi chờ phản hồi. Chúng tôi sử dụng nginx + uwsgi + django. Như bạn đã biết, Django là đồng bộ (hoặc chặn). Chúng tôi sử dụng uwsgi với đa luồng để giải quyết vấn đề với mạng IO chờ đợi. Tôi quyết định đọc về gevent. Tôi hiểu sự khác biệt giữa đa nhiệm hợp tác và ưu tiên. Và tôi hy vọng rằng gevent là giải pháp tốt hơn sau đó uwsgi chủ đề cho vấn đề này (mạng I/O nút cổ chai). Nhưng kết quả gần như giống nhau. Đôi khi gevent yếu hơn. Có thể một nơi nào đó tôi sai. Làm ơn hãy nói cho tôi.Uwsgi với gevent vs chủ đề

Đây là ví dụ về cấu hình uwsgi. Gevent:

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

Threading:

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

khiển dụ:

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 

thử nghiệm (với 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 

Trong cả hai trường hợp, tôi có thời gian tương tự. Ưu điểm của một gevent/greenlets và đa tác vụ hợp tác trong một vấn đề tương tự (API proxying) là gì?

Trả lời

5

Đồng thời 40 không phải là một cấp độ để cho phép gevent tỏa sáng. Gevent là về đồng thời không song song (hoặc hiệu suất cho mỗi yêu cầu), do đó, có một mức độ "đồng thời" thấp không phải là một cách tốt để có được những cải tiến.

Nói chung, bạn sẽ nhìn thấy đồng thời gevent với một mức độ hàng ngàn, chứ không phải 40 :)

Đối chặn đề trăn I/O được cấp không xấu (các GIL được phát hành trong I/O), lợi thế của gevent là trong việc sử dụng tài nguyên (có 1000 chủ đề python sẽ là quá mức cần thiết) và việc loại bỏ sự cần thiết phải suy nghĩ về khóa và bạn bè. Và rõ ràng, hãy nhớ rằng toàn bộ ứng dụng của bạn phải thân thiện với gevent để có được lợi thế, và django (theo mặc định) yêu cầu một chút điều chỉnh (như một adapter cơ sở dữ liệu ví dụ phải được thay đổi với một cái gì đó thân thiện với gevent).

+0

Tôi đang thử nghiệm nó với một số luồng/greenlets khác. Không phải hàng ngàn mà là hàng trăm. Và kết quả là tương tự. Tôi nghĩ rằng gevent là sự lựa chọn tốt nhất nếu tôi có nhiều hơn một yêu cầu trong hành động điều khiển của tôi (sử dụng join()/joinall()). Nhưng trong vấn đề của tôi ("proxy" -API) Tôi không có lợi ích đáng kể. Trong trường hợp đầu tiên (chủ đề) chúng ta có một cấu hình đơn giản: --threads N. Trong trường hợp thứ hai (gevent), chúng tôi có rất nhiều vấn đề với patching postgres driver (ví dụ), redis, vv. một vấn đề với dấu vết ngăn xếp đầy đủ ... – OLMER

+0

Xin lỗi, không chắc chắn để theo bạn, nếu bạn không thể "vá" django, bạn không thể sử dụng gevent, thats'it. Ứng dụng của bạn phải là 100% không chặn, nếu không nó là một ứng dụng chặn và gevent sẽ không giúp bạn (tốt, nó thậm chí sẽ làm tồi tệ nhất) – roberto

1

Phục vụ không chặn không phải về hiệu suất, đó là về sự tương tranh. Nếu 99% thời gian yêu cầu được chi tiêu trong yêu cầu phụ, bạn không thể chỉ tối ưu hóa 99% đó. Nhưng khi tất cả các chủ đề có sẵn được phục vụ bận rộn, khách hàng mới bị từ chối, mặc dù 99% thời gian của chủ đề được chi tiêu trong việc chờ hoàn thành yêu cầu phụ. Tính năng phân phát không chặn cho phép bạn sử dụng thời gian rảnh rỗi đó bằng cách chia sẻ nó giữa "trình xử lý" không bị giới hạn bởi số chuỗi có sẵn. Vì vậy, nếu 99% chờ đợi, thì 1% còn lại là xử lý CPU, do đó bạn có thể có nhiều kết nối 100x đồng thời trước khi bạn tối đa CPU của mình - không có chuỗi nhiều hơn 100x, có thể quá đắt (và với GIL của Python vấn đề, bạn phải sử dụng các tiến trình con thậm chí còn đắt hơn).

Bây giờ, như roberto đã nói, mã của bạn phải 100% không chặn để có thể cứu vãn thời gian rảnh. Tuy nhiên, như bạn có thể thấy từ ví dụ phần trăm ở trên, nó trở nên quan trọng chỉ khi các yêu cầu gần như hoàn toàn bị ràng buộc IO.Nếu đúng như vậy, có thể bạn không cần Django, ít nhất là cho phần đó của ứng dụng của bạn.

Các vấn đề liên quan