Sửa lỗi cho câu trả lời của @TemporalBying ở trên, greenlets không "nhanh" hơn các luồng và đó là một kỹ thuật lập trình không chính xác để tạo ra 60000 luồng để giải quyết vấn đề tương tranh, thay vào đó là một nhóm các luồng nhỏ. Dưới đây là một so sánh hợp lý hơn (từ bài đăng trên reddit của tôi để phản hồi lại những người trích dẫn bài đăng SO này).
import gevent
from gevent import socket as gsock
import socket as sock
import threading
from datetime import datetime
def timeit(fn, URLS):
t1 = datetime.now()
fn()
t2 = datetime.now()
print(
"%s / %d hostnames, %s seconds" % (
fn.__name__,
len(URLS),
(t2 - t1).total_seconds()
)
)
def run_gevent_without_a_timeout():
ip_numbers = []
def greenlet(domain_name):
ip_numbers.append(gsock.gethostbyname(domain_name))
jobs = [gevent.spawn(greenlet, domain_name) for domain_name in URLS]
gevent.joinall(jobs)
assert len(ip_numbers) == len(URLS)
def run_threads_correctly():
ip_numbers = []
def process():
while queue:
try:
domain_name = queue.pop()
except IndexError:
pass
else:
ip_numbers.append(sock.gethostbyname(domain_name))
threads = [threading.Thread(target=process) for i in range(50)]
queue = list(URLS)
for t in threads:
t.start()
for t in threads:
t.join()
assert len(ip_numbers) == len(URLS)
URLS_base = ['www.google.com', 'www.example.com', 'www.python.org',
'www.yahoo.com', 'www.ubc.ca', 'www.wikipedia.org']
for NUM in (5, 50, 500, 5000, 10000):
URLS = []
for _ in range(NUM):
for url in URLS_base:
URLS.append(url)
print("--------------------")
timeit(run_gevent_without_a_timeout, URLS)
timeit(run_threads_correctly, URLS)
Đây là một số kết quả:
--------------------
run_gevent_without_a_timeout / 30 hostnames, 0.044888 seconds
run_threads_correctly / 30 hostnames, 0.019389 seconds
--------------------
run_gevent_without_a_timeout / 300 hostnames, 0.186045 seconds
run_threads_correctly / 300 hostnames, 0.153808 seconds
--------------------
run_gevent_without_a_timeout / 3000 hostnames, 1.834089 seconds
run_threads_correctly / 3000 hostnames, 1.569523 seconds
--------------------
run_gevent_without_a_timeout / 30000 hostnames, 19.030259 seconds
run_threads_correctly / 30000 hostnames, 15.163603 seconds
--------------------
run_gevent_without_a_timeout / 60000 hostnames, 35.770358 seconds
run_threads_correctly / 60000 hostnames, 29.864083 seconds
sự hiểu lầm của mọi người về việc không chặn IO với Python là niềm tin rằng trình thông dịch Python có thể tham gia vào công việc truy xuất kết quả từ các socket ở quy mô lớn nhanh hơn chính các kết nối mạng có thể trả về IO. Mặc dù điều này chắc chắn đúng trong một số trường hợp, nhưng nó không đúng gần như mọi người nghĩ, bởi vì trình thông dịch Python thực sự rất chậm. Trong bài đăng trên blog của tôi ở đây , tôi minh họa một số cấu hình đồ họa cho thấy rằng ngay cả những điều rất đơn giản, nếu bạn đang xử lý truy cập mạng nhanh và sắc nét vào những thứ như cơ sở dữ liệu hoặc máy chủ DNS, các dịch vụ đó có thể quay lại nhanh hơn rất nhiều so với mã Python có thể tham dự đến hàng ngàn kết nối đó.