ガード?グローバル通訳ロック? Python の迫り来るプロセス スレッドの知識 - 開発スキル IX

        メインの記事は、Web 開発ではあまり実用的ではありません。現在、クラウド プラットフォームが普及しており、プラットフォームの機能、複数のワーカー ワーク プロセスを開いて作業を完了する CI/CD アプローチに依存していますが、マルチスレッドとマルチプロセスを使用する一部の監視ログ プラグインを除いて、Web 開発は比較的まれです。使用済み。

        まず、私が聞いた Python 開発について話しましょう。GIL、グローバル インタプリタ ロックです。

目次

GIL グローバル インタープリタ ロック

Python マルチプロセス マルチスレッド コルーチン

Python デーモン デーモン スレッド

アヒルのモデル

runserver の実行時に 2 つのスレッドが開始されるのはなぜですか


GIL グローバル インタープリタ ロック

        GIL (グローバル インタープリター ロック、グローバル インタープリター ロック) は、CPython インタープリター同期メカニズムであり、複数のスレッドをPython バイトコードを同時に実行する 1 つのスレッドのみに制限するために使用されますGIL は、メモリ管理を簡素化し、マルチスレッドでのデータ競合を解決するために存在します。

        ただし、GIL により、CPython のマルチスレッドがマルチコア CPU を最大限に活用できなくなり、CPU を大量に使用するタスクのパフォーマンスが低下します。I/O 集中型のタスクの場合は、マルチスレッド、コルーチン、または非同期 I/O を使用して同時実行性を実現できます。CPU を集中的に使用するタスクの場合は、マルチプロセッサを使用してマルチコア CPU を最大限に活用することを検討してください。

        実験: 以下は python3.6 を使用したものですが、シングルスレッドとマルチスレッドの場合、実行時間はほぼ同じです。(インターネット上には、単一スレッドの実行時間ほどではない実行結果が多数あります)
        注: GIL は CPython インタープリターにのみ適用されます。たとえば、Jython と IronPython は GIL を実装していないため、これらの実装ではマルチスレッドのパフォーマンスが向上する可能性があります。

import threading
import time

def count(n):
    while n > 0:
        n -= 1

# 单线程执行
start_time = time.time()
count(100000000)
end_time = time.time()
print("单线程执行时间:", end_time - start_time)  # 单线程执行时间: 4.452801704406738

# 多线程执行
start_time = time.time()
t1 = threading.Thread(target=count, args=(50000000,))
t2 = threading.Thread(target=count, args=(50000000,))
t1.start()
t2.start()
t1.join()
t2.join()
end_time = time.time()
print("多线程执行时间:", end_time - start_time)  # 多线程执行时间: 4.272630214691162

Python マルチプロセス マルチスレッド コルーチン

  1. threading マルチスレッド: Python 標準ライブラリには、マルチスレッド サポートを提供するモジュールがあります (上記の実験で使用されました)。グローバル インタープリター ロック (GIL) が原因で、CPython のマルチスレッドはマルチコア CPU を最大限に活用できず、CPU を大量に使用するタスクのパフォーマンスが低下します。ただし、I/O 集中型のタスクでは、マルチスレッドによってプログラムの実行効率が向上します。

  2. マルチプロセッシング: Python multiprocessing モジュールはマルチプロセッシングのサポートを提供します。マルチプロセスはマルチコア CPU を最大限に活用でき、CPU 集中型のタスクに適しています。ただし、プロセス間通信とリソース共有は比較的複雑でコストがかかります。

  3. コルーチン: コルーチンは、1 つのスレッド内で複数のタスクを同時に実行できる軽量の同時実行戦略です。コルーチンは、 async/await 非同期 I/O と構文を使用して実装されます。Python asyncio モジュールはコルーチンのサポートを提供します。コルーチンは、ネットワーク リクエスト、ファイルの読み取りと書き込みなど、I/O 集中型のタスクに適しています。

マルチプロセス実験:

import multiprocessing
import time

def count(n):
    while n > 0:
        n -= 1

def main1():
    # 单进程执行
    start_time = time.time()
    count(100000000)
    end_time = time.time()
    print("单进程执行时间:", end_time - start_time)  # 单进程执行时间: 4.279423713684082

    # 多进程执行
    start_time = time.time()
    process1 = multiprocessing.Process(target=count, args=(50000000,))
    process2 = multiprocessing.Process(target=count, args=(50000000,))
    process1.start()
    process2.start()
    process1.join()
    process2.join()
    end_time = time.time()
    print("多进程执行时间:", end_time - start_time)  # 多进程执行时间: 2.2506167888641357

if __name__ == '__main__':
    main1()

コルーチンの実験 (この実験では、マルチ コルーチンは優勢ではありません。コルーチンの主な利点は、ネットワーク リクエスト、ファイルの読み取りと書き込みなど、I/O 集約型のタスクを効率的に処理できることです)。

import asyncio
import time

async def count(n):
    while n > 0:
        n -= 1

async def main():
    task1 = asyncio.create_task(count(50000000))
    task2 = asyncio.create_task(count(50000000))
    await asyncio.gather(task1, task2)

# 单协程执行
start_time = time.time()
asyncio.run(count(100000000))
end_time = time.time()
print("单协程执行时间:", end_time - start_time)

# 多协程执行
start_time = time.time()
asyncio.run(main())
end_time = time.time()
print("多协程执行时间:", end_time - start_time)

"""
单协程执行时间: 4.209939241409302
多协程执行时间: 4.172176122665405
"""

Python デーモン デーモン スレッド

  1. デーモン: デーモンは、ユーザーの操作とは関係なく、バックグラウンドで実行されるプロセスです。デーモンは通常、ロギング、監視などのバックグラウンド タスクを実行するために使用されます。Python では、 multiprocessing.Process クラス 属性を使用してdaemon デーモンを作成できます。

  2. デーモン スレッド: デーモン スレッドはバックグラウンドで実行されるスレッドで、メイン スレッドが終了すると、デーモン スレッドも自動的に終了します。デーモン スレッドは通常、ロギング、監視などのバックグラウンド タスクを実行するために使用されます。Python では、 threading.Thread クラス 属性を使用してdaemon デーモン スレッドを作成できます。

デーモンの実験:

"""
守护进程
但这段代码不适合在windows OS上运行,适合linux
"""
import os
import sys
import time


def daemonize():
    pid = os.fork()  # 创建一个新的子进程

    if pid > 0:
        sys.exit()

    os.setsid()  # 创建一个新的会话,并将子进程设置为该会话的会话领导者。这将使子进程脱离控制终端,从而实现守护进程的特性之一。
    os.umask(0)  # 设置子进程的文件创建模式

    pid = os.fork()

    if pid > 0:
        sys.exit()

    sys.stdout.flush()
    sys.stderr.flush()

    with open("/dev/null", "r") as stdin:
        os.dup2(stdin.fileno(), sys.stdin.fileno())

    with open("/dev/null", "a") as stdout:
        os.dup2(stdout.fileno(), sys.stdout.fileno())

    with open("/dev/null", "a") as stderr:
        os.dup2(stderr.fileno(), sys.stderr.fileno())


def run():
    while True:
        print("Daemon is running...")
        time.sleep(5)


if __name__ == "__main__":
    daemonize()
    run()

デーモンスレッドの実験:

import threading
import time


def run():
    while True:
        print("Daemon thread is running...")
        time.sleep(5)


if __name__ == "__main__":
    daemon_thread = threading.Thread(target=run)  # 线程对象
    daemon_thread.daemon = True
    daemon_thread.start()  # 启动守护线程

    # 主线程将等待10秒后结束
    time.sleep(10)
    print("Main thread is terminating")

"""
Daemon thread is running...
Daemon thread is running...
Main thread is terminating
Daemon thread is running...
"""

アヒルのモデル

        ダックタイピングは、主に Python などの動的型付け言語で使用されるプログラミング概念です。アヒル モデルの中心となるアイデアは、オブジェクトの種類ではなく、オブジェクトの動作に焦点を当てることです。言い換えれば、物体がアヒルのように歩いたり鳴いたりする場合、私たちはそれをアヒルとみなし、実際の種類は気にしません。

class Duck:
    def quack(self):
        return "Quack!"

class Dog:
    def quack(self):
        return "Woof!"

def make_sound(animal):
    print(animal.quack())

duck = Duck()
dog = Dog()

make_sound(duck)  # 输出 "Quack!"
make_sound(dog)   # 输出 "Woof!"

runserver の実行時に 2 つのスレッドが開始されるのはなぜですか

Django の runserver コマンドで実行すると、通常 2 つのスレッドが開始されます。これら 2 つのスレッドの主な目的は次のとおりです。

  1. メインスレッド: このスレッドは、HTTP リクエストの処理、クライアントからのリクエストの受信、対応するビュー関数の呼び出しを行ってリクエストを処理し、最後にクライアントに応答を返す役割を果たします。このプロセス中、メインスレッドは URL ルーティング、テンプレートのレンダリング、データベース操作などのタスクを処理します。

  2. 自動リローダー スレッド: このスレッドは主に、プロジェクト内のソース コード ファイルの監視を担当します。ファイルの変更を検出すると、プロジェクトが自動的に再ロードされるため、サーバーを手動で再起動しなくても変更がすぐに有効になります。これは、開発中のデバッグや迅速な反復に非常に役立ちます

        このような設計により、コードが変更されると手動で再起動しなくてもサーバーが自動的にリロードされるため、開発プロセス中の開発者の効率が向上します。同時に、自動リロード機能を別のスレッドに配置することで、メインスレッドが常に HTTP リクエストの処理に集中できるようになり、サーバーの応答速度が向上します。

おすすめ

転載: blog.csdn.net/lxd_max/article/details/132092041