爬虫類高性能asyncio

非同期コルーチン、非同期プログラミングを実現

我々は、すべてのコルーチンの使用、非同期コルーチン中などのjs、LUA、などの同時タスクの効率的な方法は、彼らは非常に強いてきたことをIOスケジューリングを制御するためのサーバー開発の優先順位は、もはやシステムに依存していることを知っている、と希望。

Pythonのバージョン3.4はまた、コルーチンの概念に入社し、3.5は基本的な構文と完璧な実装を確立します。3.6ものawait同時に行い、収率を最適化することは、同じ制限に本体の関数として放出されます。

asyncio python3.4バージョンは標準ライブラリに導入され、python2xこのライブラリを追加していない、すべての後、ハハ、将来のpython3xああです!python3.5は非同期/のawait特性に参加しました。

外asyncio、必見最初の数字を学習する前に、同期/非同期の概念

  • event_loopイベントループ:プログラムの無限ループを開始し、プログラマはイベントループにいくつかの機能を登録します。満足事件は、適切なコルーチン関数を呼び出すとき。
  • コルーチンコルーチン:コルーチンオブジェクトは非同期キーワードを使用して定義された関数を指し、それはすぐに関数呼び出しを実行しませんが、コルーチンオブジェクトを返します。コルーチンのオブジェクトは、イベントループによって呼び出されるイベントループに登録する必要があります。
  • タスクのタスク:コルーチンの目的は、タスクがさらにコルーチンにカプセル化され、ネイティブ関数を中断することができるでは、タスクの種々の状態は、その中に含まれます。
  • 未来:将来の業績へのガイドか行われていないタスクを実行します。それとタスクの間には本質的な違いはありません
  • 非同期/のawaitキーワード:コルーチン用python3.5-定義されたキーワード、コルーチンの非同期定義は、非同期呼び出しインターフェイスをブロック中断するために待っています。

我々はまた、上述したように、そのような、完成実行するなど、より多くの比較動作状態をコルーチン内部さらにコルーチンオブジェクトにカプセル化されているタスクは、オブジェクト、我々はコルーチン実装オブジェクトを取得するためにこれらの状態を使用することができます。

1、コルーチンを作成します

まず、コルーチンを定義し、DEF追加非同期は前に宣言し、コルーチン関数を定義することができます。

コルーチン機能は、イベントループのループに加えるだけコルーチン、実行を直接呼び出すことはできません。asyncio.get_event_loopメソッドは、イベントループを作成し、イベントループに登録コルーチンrun_until_completeを使用して、イベントループを開始することができます。

例えば:

import asyncio

async def func(a):
    print('leiting':a)
corouine = func(1)

loop = asyncio.get_event_loop()
loop.run_until_complete(func())

次のように上記の例では、我々は、コルーチンの目的は、()メソッドをrun_until_completeする場合、実際にはタスク・オブジェクト内にパッケージ操作コルーチンを実行することで、我々は、明示的に宣言することができます。

import asyncio

async def execute(x):
    print('Number:', x)
    return x

coroutine = execute(1)
print('Coroutine:', coroutine)
print('After calling execute')

loop = asyncio.get_event_loop()

task = loop.create_task(coroutine)
print('Task1:', task)
#当我们将 coroutine 对象传递给 run_until_complete() 方法的时候,实际上它进行了一个操作就是将 coroutine 封装成了 task 对象,我们也可以显式地进行声明
loop.run_until_complete(task)
print('Task:', task)
print('After calling loop')

结果
#Coroutine: <coroutine object execute at 0x0000017A398CB3C8>
#After calling execute
#Task1: <Task pending coro=<execute() running at D:/Python/项目位置/test.py:17>>
#Number: 1
#Task: <Task finished coro=<execute() done, defined at D:/Python/项目位置/test.py:17> result=1>
#After calling loop

ここでは、オブジェクトにタスクコルーチンオブジェクトへのCREATE_TASK()メソッドを呼び出して、オブジェクトの後にループを定義し、次に我々はプリントアウトし、それが状態を保留して発見しました。その後、我々は、我々は、プリントアウトタスクオブジェクトを見て、その状態が終了となり見つけるだけでなく、結果は1になり見ることができます、実装されるイベントループにタスクオブジェクトを追加することがあり、私たちの定義を実行します()メソッドは、結果を返します。

また直接を通して、あるタスクオブジェクトを定義する方法がありasyncio 的 ensure_future()、以下のように我々は、ループがよくタスクは、予めオブジェクト定義することができる宣言文言していないにもかかわらず、我々は、ループによって定義することができないので、結果は、タスク・オブジェクトが返される、方法。

import asyncio

async def execute(x):
    print('Number:', x)
    return x

coroutine = execute(1)
print('Coroutine:', coroutine)
print('After calling execute')

task = asyncio.ensure_future(coroutine)
print('Task1:', task)
loop = asyncio.get_event_loop()
loop.run_until_complete(task)

结果
#Coroutine: <coroutine object execute at 0x0000016A2C34B3C8>
#After calling execute
#Task1: <Task pending coro=<execute() running at D:/Python/项目位置/test.py:17>>
#Number: 1
#Task: <Task finished coro=<execute() done, defined at D:/Python/项目位置test.py:17> result=1>
#After calling loop

これは、効果が同じであることがわかりました。

バインドのコールバック

(1)タスクのコールバックメソッドをバインドするadd_done_callback()メソッドを呼び出します。私たちは、タスクが終了したときにコールバック()メソッドを呼び出すことができ、タスクカプセル化されたオブジェクトを渡す()メソッドをコールバックし、タスクオブジェクトはまた、コールバック()メソッドにパラメータとして渡されている間、(結果のタスクオブジェクトを呼び出します)メソッドは、結果が返され得ることができます

import asyncio
import requests
async def request():
    url = 'https://www.baidu.com'
    status = requests.get(url)
    status = status.text
    return status
def callback(task):
    print('Status:', task.result())
coroutine = request()
task = asyncio.ensure_future(coroutine)
task.add_done_callback(callback)
print('Task:', task)
loop = asyncio.get_event_loop()
loop.run_until_complete(task)
print('Task:', task)

結果を得るために(2)直接呼び出しタスク実行が終了しました()メソッドの後に、結果を直接呼び出します

import asyncio
import requests
async def request():
    url = 'https://www.baidu.com'
    status = requests.get(url)
    return status
coroutine = request()
task = asyncio.ensure_future(coroutine)
print('Task:', task)
loop = asyncio.get_event_loop()
loop.run_until_complete(task)
print('Task:', task)
print('Task Result:', task.result())

#Task: <Task pending coro=<request() running at D:/Python/项目位置/test.py:53>>
#Task: <Task finished coro=<request() done, defined at D:/Python/项目位置/test.py:53> result=<Response [200]>>
#Task Result: <Response [200]>

3、マルチタスクコルーチン

その後、タスクリストの定義、および実行するために待機()メソッドasyncio使用しています。私たちは5つのタスクを作成したforループを使用して、リストを作る、そしてリストはまず待機asyncio()メソッドに転送され、時間サイクルを登録するには5つのタスクを開始することができます。最後に、我々は、タスクの結果出て実行してから、出力

import asyncio
import requests
async def request():
    url = 'https://www.baidu.com'
    status = requests.get(url)
    return status
tasks = [asyncio.ensure_future(request()) for _ in range(5)]
print('Tasks:', tasks)
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
for task in tasks:
    print('Task Result:', task.result())
    
Task Result: <Response [200]>
Task Result: <Response [200]>
Task Result: <Response [200]>
Task Result: <Response [200]>
Task Result: <Response [200]>

コルーチンを達成するために4、

(1)は、時間のかかる制御を放棄する中断のawait保留中の操作を使用することができます。コルーチン実行出会いが待っていた場合、サイクルタイムは、一時停止このコルーチンも他のコルーチンの一時停止または実行されるまで、他のコルーチンの実装になります。

import asyncio
import requests
import time
start = time.time()
async def get(url):
    return requests.get(url)
async def request():
    url = 'https://www.baidu.com'
    print('Waiting for', url)
    response = await get(url)
    print('Get response from', url, 'Result', response.status_code)
tasks = [asyncio.ensure_future(request()) for _ in range(5)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
end = time.time()
print('Cost time:', end - start)

Waiting for https://www.baidu.com
Get response from https://www.baidu.com Result 200
Waiting for https://www.baidu.com
Get response from https://www.baidu.com Result 200
Waiting for https://www.baidu.com
Get response from https://www.baidu.com Result 200
Waiting for https://www.baidu.com
Get response from https://www.baidu.com Result 200
Waiting for https://www.baidu.com
Get response from http

5、使用aiohttp

aiohttpは、非同期要求のためのサポートライブラリである、と私たちasyncioでそれを使用し、非常に簡単に、非同期要求操作を実装することができます。

ここでは、()、ライブラリはaiohttp変更要求で構成されて要求aiohttpのクラス別ClientSessionのメソッド要求を取得します

import asyncio
import aiohttp
import time
start = time.time()
async def get(url):
    session = aiohttp.ClientSession()
    response = await session.get(url)
    result = await response.text()
    await session.close()
    return result
async def request():
    url = 'http://www.newsmth.net/nForum/#!mainpage'
    print('Waiting for', url)
    result = await get(url)
    print('Get response from', url, 'Result:', result)
tasks = [asyncio.ensure_future(request()) for _ in range(5)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
end = time.time()
print('Cost time:', end - start)

私たちはあなたのawaitが発生した場合は5つのコプロセスの実装では、されるまで、他のコルーチンを実行する代わりに、現在のコルーチンを中断し、get()メソッドに続いて、のawait内のコードを使用します他のコルーチンが中断または終了し、その後、次のコルーチンを実行しますか。

最初待つために実行したときに実行を開始するには、サイクルタイムは保留中ですget()メソッド、しかし、get()メソッドの最初のステップに従って、最初のタスクのために、最初のタスクを実行します実行は次にsession.get()リクエストメソッドと呼ばれ、第二のawaitと会い、その後ので、懸濁し、それらは直ちに実装に入ったので、ClientSessionのオブジェクトを作成し、すぐに覚醒した後に中断、非ブロッキングであります要求は、時間のかかる長い時間のために、それは良い最初のタスクは、次の、どのようにそれを行うには、中断され、覚醒していません必要?イベントループは現在、彼は2番目のタスクの実装になったので、プロセスはすべて、session.get第五タスク()メソッドの実行後まで、同じ操作で、コルーチンが継続中断されていないように見えますタスクがハングアップされています。すべてのタスクが中断状態にされている、それがになっていますか?私は待たなければなりませんでした。3秒後、いくつかの要求がほぼ同時に応答を有し、その後も行われるいくつかのタスクを覚ます、要求の出力結果は、最終的に3秒かかります!

どうでしょうか?そして、これは非同期操作が提供する利便性、それは操作を阻止することになると、タスクが中断され、むしろ無邪気を待っているよりも、他のタスクを実行するためのプログラムですので、あなたは時間を無駄にすることなく、CPU時間をフルに活用することができますIOを待っています。

おすすめ

転載: www.cnblogs.com/leiting7/p/11974584.html