ホームページ バックエンド開発 Python チュートリアル Python の非同期をマスターする: コルーチンとイベント ループでアプリのパフォーマンスを向上させる

Python の非同期をマスターする: コルーチンとイベント ループでアプリのパフォーマンスを向上させる

Nov 17, 2024 am 08:53 AM

Mastering Python

Python の非同期プログラミングは、高性能アプリケーションの構築に大きな変革をもたらします。私はこれを何年も使っていますが、正しく使えばどれほど強力になるかにいつも驚かされます。

Python の非同期モデルの中心となるのは、コルーチンとイベント ループです。コルーチンは、実行を一時停止および再開できる特別な関数であり、スレッドのオーバーヘッドなしで効率的なマルチタスクを可能にします。一方、イベント ループは、これらのコルーチンを駆動し、実行を管理し、I/O 操作を処理するエンジンです。

コルーチンから始めましょう。 Python では、async def 構文を使用して定義します。簡単な例を次に示します:

async def greet(name):
    print(f"Hello, {name}!")
    await asyncio.sleep(1)
    print(f"Goodbye, {name}!")
ログイン後にコピー
ログイン後にコピー

このコルーチンは人に挨拶し、少し待ってから別れを告げます。ここでは await キーワードが重要です。これにより、コルーチンが実行を一時停止し、制御をイベント ループに戻すことができます。

しかし、コルーチンは内部でどのように機能するのでしょうか?これらは実際には、Python のジェネレーター機能の上に構築されています。コルーチンを呼び出しても、すぐには実行されません。代わりに、コルーチン オブジェクトを返します。このオブジェクトは、ジェネレーターと同様に、値を送信したり、値を生成したりできます。

イベント ループは、これらのコルーチンを実際に実行する役割を果たします。タスク (コルーチンのラッパー) のキューを維持し、それらを 1 つずつ実行します。コルーチンが await ステートメントに到達すると、イベント ループはそれを一時停止し、次のタスクに進みます。これが協調的なマルチタスクの本質です。タスクは自発的に制御を放棄し、他のタスクが実行できるようにします。

イベント ループがどのように機能するかを簡略化して示します。

class EventLoop:
    def __init__(self):
        self.ready = deque()
        self.sleeping = []

    def call_soon(self, callback):
        self.ready.append(callback)

    def call_later(self, delay, callback):
        deadline = time.time() + delay
        heapq.heappush(self.sleeping, (deadline, callback))

    def run_forever(self):
        while True:
            self.run_once()

    def run_once(self):
        now = time.time()
        while self.sleeping and self.sleeping[0][0] <= now:
            _, callback = heapq.heappop(self.sleeping)
            self.ready.append(callback)

        if self.ready:
            callback = self.ready.popleft()
            callback()
        else:
            time.sleep(0.1)  # Avoid busy waiting
ログイン後にコピー
ログイン後にコピー

このイベント ループは、実行準備ができているタスク (準備完了キュー内) とスリープ中のタスク (スリープ リスト内) の 2 種類のタスクを管理します。 run_forever メソッドは、タスクがなくなるまでタスクを実行し続けます。

それでは、タスクのスケジュール設定について話しましょう。 Python の asyncio モジュールは、高度なスケジューリング機能を備えた、より洗練されたイベント ループを提供します。 I/O 操作を処理し、サブプロセスを実行し、他のイベント ループと統合することもできます。

asyncio を使用して複数のコルーチンを同時に実行する方法は次のとおりです。

import asyncio

async def task1():
    print("Task 1 starting")
    await asyncio.sleep(2)
    print("Task 1 finished")

async def task2():
    print("Task 2 starting")
    await asyncio.sleep(1)
    print("Task 2 finished")

async def main():
    await asyncio.gather(task1(), task2())

asyncio.run(main())
ログイン後にコピー
ログイン後にコピー

このスクリプトは両方のタスクを開始しますが、タスク 2 はスリープ時間が短いため、タスク 1 よりも前に終了します。

非同期プログラミングの最も強力なアプリケーションの 1 つは、ネットワーク操作です。単純な非同期 Web サーバーを見てみましょう:

import asyncio

async def handle_client(reader, writer):
    data = await reader.read(100)
    message = data.decode()
    addr = writer.get_extra_info('peername')

    print(f"Received {message!r} from {addr!r}")

    response = f"Echo: {message}\n"
    writer.write(response.encode())
    await writer.drain()

    print("Close the connection")
    writer.close()

async def main():
    server = await asyncio.start_server(
        handle_client, '127.0.0.1', 8888)

    addr = server.sockets[0].getsockname()
    print(f'Serving on {addr}')

    async with server:
        await server.serve_forever()

asyncio.run(main())
ログイン後にコピー
ログイン後にコピー

このサーバーはスレッドを使用せずに複数のクライアントを同時に処理できるため、非常に効率的です。

しかし、非同期プログラミングはサーバーだけのものではありません。これは、特に複数のネットワーク要求を行う必要がある場合に、クライアントにとっても最適です。これは、複数のページを同時にフェッチできるシンプルな Web スクレイパーです:

async def greet(name):
    print(f"Hello, {name}!")
    await asyncio.sleep(1)
    print(f"Goodbye, {name}!")
ログイン後にコピー
ログイン後にコピー

このスクレイパーは複数のページを同時にフェッチできるため、同期アプローチと比較してプロセスが大幅に高速化されます。

ここで、より高度な概念をいくつか見ていきましょう。 Python の非同期モデルの興味深い機能の 1 つは、独自のイベント ループを作成できることです。これは、非同期コードを他のフレームワークと統合する必要がある場合、または特定のユースケースに合わせて最適化したい場合に役立ちます。

これは、同期コールバックと非同期コールバックの両方を実行できる単純なカスタム イベント ループです。

class EventLoop:
    def __init__(self):
        self.ready = deque()
        self.sleeping = []

    def call_soon(self, callback):
        self.ready.append(callback)

    def call_later(self, delay, callback):
        deadline = time.time() + delay
        heapq.heappush(self.sleeping, (deadline, callback))

    def run_forever(self):
        while True:
            self.run_once()

    def run_once(self):
        now = time.time()
        while self.sleeping and self.sleeping[0][0] <= now:
            _, callback = heapq.heappop(self.sleeping)
            self.ready.append(callback)

        if self.ready:
            callback = self.ready.popleft()
            callback()
        else:
            time.sleep(0.1)  # Avoid busy waiting
ログイン後にコピー
ログイン後にコピー

このカスタム ループは非常に基本的なものですが、中心となる原則を示しています。これを拡張して、I/O 操作やタイマーなどのより複雑なシナリオを処理できます。

非同期コードのデバッグは、特に複雑なアプリケーションを扱う場合には困難になることがあります。私が便利だと思うテクニックの 1 つは、asyncio のデバッグ モードを使用することです。次のように有効にできます:

import asyncio

async def task1():
    print("Task 1 starting")
    await asyncio.sleep(2)
    print("Task 1 finished")

async def task2():
    print("Task 2 starting")
    await asyncio.sleep(1)
    print("Task 2 finished")

async def main():
    await asyncio.gather(task1(), task2())

asyncio.run(main())
ログイン後にコピー
ログイン後にコピー

これにより、完了しないコルーチンや実行に時間がかかりすぎるコールバックなどに関する、より詳細なエラー メッセージと警告が表示されます。

もう 1 つの便利なデバッグ手法は、asyncio のタスク イントロスペクション機能を使用することです。たとえば、実行中のすべてのタスクのリストを取得できます:

import asyncio

async def handle_client(reader, writer):
    data = await reader.read(100)
    message = data.decode()
    addr = writer.get_extra_info('peername')

    print(f"Received {message!r} from {addr!r}")

    response = f"Echo: {message}\n"
    writer.write(response.encode())
    await writer.drain()

    print("Close the connection")
    writer.close()

async def main():
    server = await asyncio.start_server(
        handle_client, '127.0.0.1', 8888)

    addr = server.sockets[0].getsockname()
    print(f'Serving on {addr}')

    async with server:
        await server.serve_forever()

asyncio.run(main())
ログイン後にコピー
ログイン後にコピー

これは、プログラムがその時点で何を行っているかを理解するのに役立ちます。

非同期コードを最適化する場合、重要な原則の 1 つは、同期操作にかかる時間を最小限に抑えることです。長時間実行される同期コードはイベント ループをブロックし、他のコルーチンの実行を妨げます。 CPU を集中的に使用するタスクがある場合は、別のスレッドまたはプロセスで実行することを検討してください。

もう 1 つの最適化テクニックは、同時に実行できるコルーチンが複数ある場合に asyncio.gather を使用することです。これは、それらを 1 つずつ待つよりも効率的です:

import asyncio
import aiohttp

async def fetch_page(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    urls = [
        'http://example.com',
        'http://example.org',
        'http://example.net'
    ]

    async with aiohttp.ClientSession() as session:
        tasks = [fetch_page(session, url) for url in urls]
        pages = await asyncio.gather(*tasks)

    for url, page in zip(urls, pages):
        print(f"Page from {url}: {len(page)} bytes")

asyncio.run(main())
ログイン後にコピー

最後に、非同期プログラミングが常に最良の解決策であるとは限らないことを覚えておいてください。待機時間が長い I/O バウンドのタスクの場合、パフォーマンスが大幅に向上します。ただし、CPU に依存するタスクの場合は、従来のマルチスレッドまたはマルチプロセッシングの方が適切な場合があります。

結論として、コルーチンとイベント ループに基づいて構築された Python の非同期プログラミング モデルは、効率的でスケーラブルなアプリケーションを作成するための強力な方法を提供します。 Web サーバー、ネットワーク クライアント、データ処理パイプラインのいずれを構築している場合でも、これらの概念を理解すると、Python の非同期機能を最大限に活用することができます。他の強力なツールと同様、効果的に使用するには練習と慎重な思考が必要ですが、結果は本当に印象的です。


私たちの作品

私たちの作品をぜひチェックしてください:

インベスターセントラル | スマートな暮らし | エポックとエコー | 不可解な謎 | ヒンドゥーヴァ | エリート開発者 | JS スクール


私たちは中程度です

Tech Koala Insights | エポックズ&エコーズワールド | インベスター・セントラル・メディア | 不可解なミステリー中 | 科学とエポックミディアム | 現代ヒンドゥーヴァ

以上がPython の非同期をマスターする: コルーチンとイベント ループでアプリのパフォーマンスを向上させるの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Python vs. C:曲線と使いやすさの学習 Python vs. C:曲線と使いやすさの学習 Apr 19, 2025 am 12:20 AM

Pythonは学習と使用が簡単ですが、Cはより強力ですが複雑です。 1。Python構文は簡潔で初心者に適しています。動的なタイピングと自動メモリ管理により、使いやすくなりますが、ランタイムエラーを引き起こす可能性があります。 2.Cは、高性能アプリケーションに適した低レベルの制御と高度な機能を提供しますが、学習しきい値が高く、手動メモリとタイプの安全管理が必要です。

Pythonと時間:勉強時間を最大限に活用する Pythonと時間:勉強時間を最大限に活用する Apr 14, 2025 am 12:02 AM

限られた時間でPythonの学習効率を最大化するには、PythonのDateTime、時間、およびスケジュールモジュールを使用できます。 1. DateTimeモジュールは、学習時間を記録および計画するために使用されます。 2。時間モジュールは、勉強と休息の時間を設定するのに役立ちます。 3.スケジュールモジュールは、毎週の学習タスクを自動的に配置します。

Python vs. C:パフォーマンスと効率の探索 Python vs. C:パフォーマンスと効率の探索 Apr 18, 2025 am 12:20 AM

Pythonは開発効率でCよりも優れていますが、Cは実行パフォーマンスが高くなっています。 1。Pythonの簡潔な構文とリッチライブラリは、開発効率を向上させます。 2.Cのコンピレーションタイプの特性とハードウェア制御により、実行パフォーマンスが向上します。選択を行うときは、プロジェクトのニーズに基づいて開発速度と実行効率を比較検討する必要があります。

Pythonの学習:2時間の毎日の研究で十分ですか? Pythonの学習:2時間の毎日の研究で十分ですか? Apr 18, 2025 am 12:22 AM

Pythonを1日2時間学ぶだけで十分ですか?それはあなたの目標と学習方法に依存します。 1)明確な学習計画を策定し、2)適切な学習リソースと方法を選択します。3)実践的な実践とレビューとレビューと統合を練習および統合し、統合すると、この期間中にPythonの基本的な知識と高度な機能を徐々に習得できます。

Python vs. C:重要な違​​いを理解します Python vs. C:重要な違​​いを理解します Apr 21, 2025 am 12:18 AM

PythonとCにはそれぞれ独自の利点があり、選択はプロジェクトの要件に基づいている必要があります。 1)Pythonは、簡潔な構文と動的タイピングのため、迅速な開発とデータ処理に適しています。 2)Cは、静的なタイピングと手動メモリ管理により、高性能およびシステムプログラミングに適しています。

Python Standard Libraryの一部はどれですか:リストまたは配列はどれですか? Python Standard Libraryの一部はどれですか:リストまたは配列はどれですか? Apr 27, 2025 am 12:03 AM

PythonListSarePartOfThestAndardarenot.liestareBuilting-in、versatile、forStoringCollectionsのpythonlistarepart。

Python:自動化、スクリプト、およびタスク管理 Python:自動化、スクリプト、およびタスク管理 Apr 16, 2025 am 12:14 AM

Pythonは、自動化、スクリプト、およびタスク管理に優れています。 1)自動化:OSやShutilなどの標準ライブラリを介してファイルバックアップが実現されます。 2)スクリプトの書き込み:Psutilライブラリを使用してシステムリソースを監視します。 3)タスク管理:スケジュールライブラリを使用してタスクをスケジュールします。 Pythonの使いやすさと豊富なライブラリサポートにより、これらの分野で優先ツールになります。

科学コンピューティングのためのPython:詳細な外観 科学コンピューティングのためのPython:詳細な外観 Apr 19, 2025 am 12:15 AM

科学コンピューティングにおけるPythonのアプリケーションには、データ分析、機械学習、数値シミュレーション、視覚化が含まれます。 1.numpyは、効率的な多次元配列と数学的関数を提供します。 2。ScipyはNumpy機能を拡張し、最適化と線形代数ツールを提供します。 3. Pandasは、データ処理と分析に使用されます。 4.matplotlibは、さまざまなグラフと視覚的な結果を生成するために使用されます。

See all articles