同期、非同期(gevent,asyncio)、マルチスレッド(threading)効率比較
4185 ワード
3つのケースで50ページを収集するのに要する時間を比較すると,マルチスレッドはgeventよりも効率的にはるかに高いことが分かった.最初のテストではmonkeyというパッチは使用されず、socketは呼び出しをブロックし、効率は向上しなかった.同期して実行されたため、monkeyパッチを使用すると、socketをコラボレーション実行に変え、効率が大幅に向上した.
Pythonの実行環境では、モジュール、クラス、関数など、実行時にほとんどのオブジェクトを変更できます.これは一般的に驚くべき悪いアイデアです.それは「暗黙的な副作用」を生み出したため、問題が発生するとデバッグが非常に難しいことが多いからです.とはいえ、極端な場合、ライブラリがPython自体の基礎的な動作を修正する必要がある場合、サルパッチが役に立ちます.この場合、geventは、socket、ssl、threading、selectなどのモジュールを含む標準ライブラリの大部分のブロックシステム呼び出しを修正し、コラボレーション実行に変更することができます.
例えば、Redisのpythonバインディングは、通常のtcp socketを使用してredis−serverインスタンスと通信する.gevent.を簡単に呼び出すことでmonkey.patch_all()は、redisのバインドコラボレーション式のスケジューリング要求をgeventスタックの他の部分と一緒に動作させることができる.
これにより、コードを1行でも書かずにgeventと共同で作業できないライブラリを組み合わせることができます.サルパッチは依然として邪悪(evil)であるが、この場合は「役に立つ邪悪(useful evil)」である.
実行結果はそれぞれ
同期実行:4.50 s gevent非同期:0.47 s threadingマルチスレッド:0.58 s更新asyncio:1.1 s geventは同時に実行するのではなく、順次実行するのか、出力結果を乱さず、マルチスレッドは順次実行せず、出力結果を乱す.ネットワークの状況が良い(IO操作の遅延が低い)場合、geventは少し効率を高めることができ、IO操作が時間がかかる場合はgevent効率が大幅に向上し、効率が最も高いのはマルチスレッドです.
djangoの下に置いてページ生成を表示する時間
同期:19065 ms gevent:1555 ms threading:166 ms
更新
python 3を追加します.5でasyncioテストを行い、geventとthreadingより少し長い1.1 s
Pythonの実行環境では、モジュール、クラス、関数など、実行時にほとんどのオブジェクトを変更できます.これは一般的に驚くべき悪いアイデアです.それは「暗黙的な副作用」を生み出したため、問題が発生するとデバッグが非常に難しいことが多いからです.とはいえ、極端な場合、ライブラリがPython自体の基礎的な動作を修正する必要がある場合、サルパッチが役に立ちます.この場合、geventは、socket、ssl、threading、selectなどのモジュールを含む標準ライブラリの大部分のブロックシステム呼び出しを修正し、コラボレーション実行に変更することができます.
例えば、Redisのpythonバインディングは、通常のtcp socketを使用してredis−serverインスタンスと通信する.gevent.を簡単に呼び出すことでmonkey.patch_all()は、redisのバインドコラボレーション式のスケジューリング要求をgeventスタックの他の部分と一緒に動作させることができる.
これにより、コードを1行でも書かずにgeventと共同で作業できないライブラリを組み合わせることができます.サルパッチは依然として邪悪(evil)であるが、この場合は「役に立つ邪悪(useful evil)」である.
実行結果はそれぞれ
同期実行:4.50 s gevent非同期:0.47 s threadingマルチスレッド:0.58 s更新asyncio:1.1 s geventは同時に実行するのではなく、順次実行するのか、出力結果を乱さず、マルチスレッドは順次実行せず、出力結果を乱す.ネットワークの状況が良い(IO操作の遅延が低い)場合、geventは少し効率を高めることができ、IO操作が時間がかかる場合はgevent効率が大幅に向上し、効率が最も高いのはマルチスレッドです.
gevent: greenlet IO , , greenlet, IO , 。 IO , , gevent , greenlet , IO。
gevent-廖雪峰の公式サイト# /usr/bin/python3
# -*- coding: utf-8 -*-
# Copyright (c) 2017 - walker
import gevent
import requests
import re
import timeit
import codecs
from threading import Thread
from gevent import monkey
monkey.patch_socket()
def get_title(url,title_list=[]):
try:
r = requests.get(url,timeout=5)
r.encoding = 'utf8'
html = r.text
title = re.search(r'(.*?) ',html).group(1)
except TimeoutError:
title = ''
if title:
title_list.append(title)
return title
def get_url():
baseurl = 'http://www.baidu.com/s?cl=3&tn=baidutop10&fr=top1000&wd=%s'
f = codecs.open('muci.txt','r','utf8')
url_list = []
for key in f.readlines():
url_list.append(baseurl % key.strip())
return url_list
url_list = get_url()
def run1():
title_list = []
for url in url_list:
get_title(url,title_list)
# title_list.append(title)
print('Sync result length:',len(title_list),title_list)
return title_list
def run2():
title_list = []
threads = [gevent.spawn(get_title,url,title_list) for url in url_list]
gevent.joinall(threads)
# title_list = [thread.value for thread in threads]
print('gevent result length:',len(title_list),title_list)
return title_list
def run3():
title_list = []
th = []
for url in url_list:
t = Thread(target=get_title,args=(url,title_list))
th.append(t)
t.start()
for t in th:
t.join()
print('threading result length:',len(title_list),title_list)
return title_list
if __name__ == '__main__':
t1 = timeit.timeit('run1()',setup="from __main__ import run1",number=1)
print('sync time:',t1)
t2 = timeit.timeit('run2()',setup="from __main__ import run2",number=1)
print('gevent time:',t2)
t3 = timeit.timeit('run3()',setup="from __main__ import run3",number=1)
print('thread time:',t3)
djangoの下に置いてページ生成を表示する時間
同期:19065 ms gevent:1555 ms threading:166 ms
更新
python 3を追加します.5でasyncioテストを行い、geventとthreadingより少し長い1.1 s
async def get_title2():
loop = asyncio.get_event_loop()
title_list = []
io = []
for url in url_list:
# get_title(url, title_list)
io.append(loop.run_in_executor(None,get_title,url,title_list))
for i in io:
await i
print(threading.current_thread(), 'Sync result length:', len(title_list), title_list)
return title_list
def run4():
loop = asyncio.get_event_loop()
loop.run_until_complete(get_title2())
if __name__ == '__main__':
global url_list
url_list = get_url()
t4 = timeit.timeit('run4()', setup="from __main__ import run4", number=1)
print('thread time:', t4)