Mengoreksi jawaban @TemporalBeing di atas, greenlets tidak "lebih cepat" dari utas dan itu adalah teknik pemrograman yang salah untuk menelurkan 60000 utas untuk memecahkan masalah konkurensi, sekelompok kecil utas bukannya sesuai. Berikut ini adalah perbandingan yang lebih masuk akal (dari posting reddit saya dalam menanggapi orang-orang yang mengutip posting SO ini).
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)
Berikut ini beberapa hasilnya:
--------------------
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
kesalahpahaman yang dimiliki setiap orang tentang non-pemblokiran IO dengan Python adalah keyakinan bahwa juru bahasa Python dapat menangani pekerjaan mengambil hasil dari soket pada skala besar lebih cepat daripada koneksi jaringan itu sendiri dapat mengembalikan IO. Walaupun ini memang benar dalam beberapa kasus, itu tidak benar hampir sesering yang dipikirkan orang, karena interpreter Python benar-benar lambat. Dalam posting blog saya di sini , saya mengilustrasikan beberapa profil grafis yang menunjukkan bahwa untuk hal-hal yang sangat sederhana sekalipun, jika Anda berurusan dengan akses jaringan yang tajam dan cepat ke hal-hal seperti database atau server DNS, layanan tersebut dapat kembali jauh lebih cepat daripada kode Python dapat menangani ribuan koneksi tersebut.