Python スレッドの完了を待つ方法

PythonPythonBeginner
オンラインで実践に進む

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

Python スレッドの完了を待つ方法を習得することは、堅牢で信頼性の高いアプリケーションを構築するために不可欠です。マルチスレッドプログラムでは、適切な同期により、操作が正しい順序で完了し、リソースが効率的に使用されることが保証されます。

この実験(Lab)では、Python スレッドを作成し、それらの完了を待ち、複数のスレッドを処理する方法を学びます。これらのスキルは、適切な同期を維持しながら、複数のタスクを同時に実行できる並行アプリケーションを開発するための基礎となります。

最初の Python スレッドの作成

Python の threading モジュールは、スレッドを簡単に作成および管理する方法を提供します。このステップでは、基本的なスレッドを作成し、その動作を観察する方法を学びます。

スレッドの理解

スレッドは、プログラム内の個別の実行フローです。Python スクリプトを実行すると、メインスレッドと呼ばれる単一のスレッドから開始されます。追加のスレッドを作成することにより、プログラムは複数のタスクを同時に実行できます。

スレッドは、以下の場合に役立ちます。

  • メインプログラムをブロックせずに、時間のかかる操作を実行する
  • パフォーマンスを向上させるためにタスクを並行して処理する
  • サーバーアプリケーションで複数のクライアント接続を処理する

簡単なスレッドの作成

スレッドを作成して開始する方法を示す簡単な Python スクリプトを作成することから始めましょう。

  1. 「File」メニューをクリックし、「New File」を選択して、エディターで新しいファイルを開き、/home/labex/project ディレクトリに simple_thread.py として保存します。

  2. 次のコードをファイルに追加します。

import threading
import time

def print_numbers():
    """Function that prints numbers from 1 to 5 with a delay."""
    for i in range(1, 6):
        print(f"Number {i} from thread")
        time.sleep(1)  ## Sleep for 1 second

## Create a thread that targets the print_numbers function
number_thread = threading.Thread(target=print_numbers)

## Start the thread
print("Starting the thread...")
number_thread.start()

## Main thread continues execution
print("Main thread continues to run...")
print("Main thread is doing other work...")

## Sleep for 2 seconds to demonstrate both threads running concurrently
time.sleep(2)
print("Main thread finished its work!")
  1. Ctrl+S を押すか、「File」>「Save」をクリックしてファイルを保存します。

  2. ターミナルを開き(まだ開いていない場合)、次を実行してスクリプトを実行します。

python3 /home/labex/project/simple_thread.py

次のような出力が表示されるはずです。

Starting the thread...
Main thread continues to run...
Main thread is doing other work...
Number 1 from thread
Number 2 from thread
Main thread finished its work!
Number 3 from thread
Number 4 from thread
Number 5 from thread

何が起こったかの分析

この例では、次のことが行われました。

  1. threading モジュールと time モジュールをインポートしました。
  2. 各数字の間に 1 秒の遅延を置いて、1 から 5 までの数字を出力する関数 print_numbers() を定義しました。
  3. target パラメータを使用して、実行する関数を指定して、スレッドオブジェクトを作成しました。
  4. start() メソッドを使用してスレッドを開始しました。
  5. メインスレッドは実行を継続し、メッセージを出力し、2 秒間スリープしました。
  6. メインスレッドと数字スレッドの両方が同時に実行されたため、出力がインターリーブされました。

メインスレッドは、数字スレッドがすべての数字を出力する前に終了したことに注意してください。これは、スレッドが独立して実行され、デフォルトでは、他のスレッドがまだ実行されていても、メインスレッドが終了すると Python プログラムが終了するためです。

次のステップでは、join() メソッドを使用してスレッドの完了を待つ方法を学びます。

join() を使用してスレッドの完了を待つ

前のステップでは、メインスレッドとは独立して実行されるスレッドを作成しました。ただし、プログラムの残りの部分に進む前に、スレッドがその作業を完了するのを待つ必要がある状況が数多くあります。ここで join() メソッドが役立ちます。

join() メソッドの理解

スレッドオブジェクトの join() メソッドは、join() メソッドが呼び出されたスレッドが終了するまで、呼び出し元のスレッド(通常はメインスレッド)をブロックします。これは、以下の場合に不可欠です。

  • メインスレッドがワーカー(worker)スレッドからの結果を必要とする場合
  • プログラムを終了する前に、すべてのスレッドが完了していることを確認する必要がある場合
  • 操作の順序がアプリケーションロジックにとって重要である場合

スレッドの作成と完了の待機

join() メソッドを使用してスレッドの完了を待つ方法を示すために、前の例を変更してみましょう。

  1. /home/labex/project ディレクトリに join_thread.py という名前の新しいファイルを作成します。

  2. 次のコードをファイルに追加します。

import threading
import time

def calculate_sum(numbers):
    """Function that calculates the sum of numbers with a delay."""
    print("Starting the calculation...")
    time.sleep(3)  ## Simulate a time-consuming calculation
    result = sum(numbers)
    print(f"Calculation result: {result}")
    return result

## Create a list of numbers
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

## Create a thread that targets the calculate_sum function
calculation_thread = threading.Thread(target=calculate_sum, args=(numbers,))

## Start the thread
print("Main thread: Starting the calculation thread...")
calculation_thread.start()

## Do some other work in the main thread
print("Main thread: Doing some other work while waiting...")
for i in range(5):
    print(f"Main thread: Working... ({i+1}/5)")
    time.sleep(0.5)

## Wait for the calculation thread to complete
print("Main thread: Waiting for the calculation thread to finish...")
calculation_thread.join()
print("Main thread: Calculation thread has finished!")

## Continue with the main thread
print("Main thread: Continuing with the rest of the program...")
  1. ファイルを保存し、次のコマンドで実行します。
python3 /home/labex/project/join_thread.py

次のような出力が表示されるはずです。

Main thread: Starting the calculation thread...
Starting the calculation...
Main thread: Doing some other work while waiting...
Main thread: Working... (1/5)
Main thread: Working... (2/5)
Main thread: Working... (3/5)
Main thread: Working... (4/5)
Main thread: Working... (5/5)
Main thread: Waiting for the calculation thread to finish...
Calculation result: 55
Main thread: Calculation thread has finished!
Main thread: Continuing with the rest of the program...

join() の重要性

この例では、次のことが行われました。

  1. 計算(数値の合計)を実行するスレッドを作成しました。
  2. メインスレッドは、他の作業を同時に行いました。
  3. メインスレッドが計算が完了していることを確認する必要がある場合、calculation_thread.join() を呼び出しました。
  4. join() メソッドにより、メインスレッドは計算スレッドが終了するまで待機しました。
  5. 計算スレッドが完了した後、メインスレッドは実行を継続しました。

このパターンは、プログラムの残りの部分に進む前に、すべてのスレッド化されたタスクが完了していることを確認する必要がある場合に非常に役立ちます。join() がないと、メインスレッドは、ワーカー(worker)スレッドがタスクを完了する前に続行し、終了することさえあります。

タイムアウトを使用した join() の使用

場合によっては、スレッドを待ちたいが、無期限に待機したくない場合があります。join() メソッドは、待機する最大秒数を指定するオプションのタイムアウトパラメータを受け入れます。

これを実証するために、コードを変更してみましょう。

  1. /home/labex/project ディレクトリに join_timeout.py という名前の新しいファイルを作成します。

  2. 次のコードを追加します。

import threading
import time

def long_running_task():
    """A function that simulates a very long-running task."""
    print("Long-running task started...")
    time.sleep(10)  ## Simulate a 10-second task
    print("Long-running task completed!")

## Create and start the thread
task_thread = threading.Thread(target=long_running_task)
task_thread.start()

## Wait for the thread to complete, but only for up to 3 seconds
print("Main thread: Waiting for up to 3 seconds...")
task_thread.join(timeout=3)

## Check if the thread is still running
if task_thread.is_alive():
    print("Main thread: The task is still running, but I'm continuing anyway!")
else:
    print("Main thread: The task has completed within the timeout period.")

## Continue with the main thread
print("Main thread: Continuing with other operations...")
## Let's sleep a bit to see the long-running task complete
time.sleep(8)
print("Main thread: Finished.")
  1. ファイルを保存して実行します。
python3 /home/labex/project/join_timeout.py

出力は次のようになります。

Long-running task started...
Main thread: Waiting for up to 3 seconds...
Main thread: The task is still running, but I'm continuing anyway!
Main thread: Continuing with other operations...
Long-running task completed!
Main thread: Finished.

この例では、メインスレッドは、タスクスレッドが完了するまで最大 3 秒間待ちます。タスクに 10 秒かかるため、メインスレッドはタイムアウト後に続行し、タスクスレッドはバックグラウンドで実行を続けます。

このアプローチは、スレッドに完了する機会を与えたいが、一定の時間が経過した後に何があっても続行する必要がある場合に役立ちます。

複数のスレッドの操作

実際のアプリケーションでは、多くの場合、複数のスレッドを同時に操作する必要があります。このステップでは、Python で複数のスレッドを作成、管理、および同期する方法を学びます。

複数のスレッドの作成

複数の同様のタスクを扱う場合、それらを同時に処理するために複数のスレッドを作成するのが一般的です。これは、特にファイルのダウンロードやネットワークリクエストなどの I/O バウンド操作の場合、パフォーマンスを大幅に向上させることができます。

複数のスレッドを使用してタスクのリストを処理する例を作成しましょう。

  1. /home/labex/project ディレクトリに multiple_threads.py という名前の新しいファイルを作成します。

  2. 次のコードを追加します。

import threading
import time
import random

def process_task(task_id):
    """Function to process a single task."""
    print(f"Starting task {task_id}...")
    ## Simulate variable processing time
    processing_time = random.uniform(1, 3)
    time.sleep(processing_time)
    print(f"Task {task_id} completed in {processing_time:.2f} seconds.")
    return task_id

## List of tasks to process
tasks = list(range(1, 6))  ## Tasks with IDs 1 through 5

## Create a list to store our threads
threads = []

## Create and start a thread for each task
for task_id in tasks:
    thread = threading.Thread(target=process_task, args=(task_id,))
    threads.append(thread)
    print(f"Created thread for task {task_id}")
    thread.start()

print(f"All {len(threads)} threads have been started")

## Wait for all threads to complete
for thread in threads:
    thread.join()

print("All tasks have been completed!")
  1. ファイルを保存して実行します。
python3 /home/labex/project/multiple_threads.py

出力は、ランダムな処理時間のために毎回異なりますが、次のようなものになるはずです。

Created thread for task 1
Starting task 1...
Created thread for task 2
Starting task 2...
Created thread for task 3
Starting task 3...
Created thread for task 4
Starting task 4...
Created thread for task 5
Starting task 5...
All 5 threads have been started
Task 1 completed in 1.23 seconds.
Task 3 completed in 1.45 seconds.
Task 2 completed in 1.97 seconds.
Task 5 completed in 1.35 seconds.
Task 4 completed in 2.12 seconds.
All tasks have been completed!

実行フローの理解

この例では、次のことが行われました。

  1. ランダムな期間でタスクを処理する process_task() 関数を定義しました。
  2. タスク ID のリスト(1 から 5)を作成しました。
  3. 各タスクに対して、スレッドを作成し、リストに保存して開始しました。
  4. すべてのスレッドを開始した後、2 番目のループで join() を使用して、各スレッドが完了するのを待ちました。
  5. すべてのスレッドが完了した後にのみ、最終的なメッセージを出力しました。

このパターンは、並行して処理できる一連の独立したタスクがある場合に非常に役立ちます。

スレッドプールエグゼキュータ(Thread Pool Executors)

より高度なスレッド管理のために、Python の concurrent.futures モジュールは ThreadPoolExecutor クラスを提供します。これは、再利用できるワーカー(worker)スレッドのプールを作成します。これは、各タスクに対してスレッドを作成および破棄するよりも効率的です。

スレッドプールを使用して例を書き直しましょう。

  1. /home/labex/project ディレクトリに thread_pool.py という名前の新しいファイルを作成します。

  2. 次のコードを追加します。

import concurrent.futures
import time
import random

def process_task(task_id):
    """Function to process a single task."""
    print(f"Starting task {task_id}...")
    ## Simulate variable processing time
    processing_time = random.uniform(1, 3)
    time.sleep(processing_time)
    print(f"Task {task_id} completed in {processing_time:.2f} seconds.")
    return f"Result of task {task_id}"

## List of tasks to process
tasks = list(range(1, 6))  ## Tasks with IDs 1 through 5

## Create a ThreadPoolExecutor
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
    ## Submit all tasks and store the Future objects
    print(f"Submitting {len(tasks)} tasks to the thread pool with 3 workers...")
    future_to_task = {executor.submit(process_task, task_id): task_id for task_id in tasks}

    ## As each task completes, get its result
    for future in concurrent.futures.as_completed(future_to_task):
        task_id = future_to_task[future]
        try:
            result = future.result()
            print(f"Got result from task {task_id}: {result}")
        except Exception as e:
            print(f"Task {task_id} generated an exception: {e}")

print("All tasks have been processed!")
  1. ファイルを保存して実行します。
python3 /home/labex/project/thread_pool.py

出力は、ランダムな処理時間のために再び異なりますが、次のようなものになるはずです。

Submitting 5 tasks to the thread pool with 3 workers...
Starting task 1...
Starting task 2...
Starting task 3...
Task 2 completed in 1.15 seconds.
Starting task 4...
Got result from task 2: Result of task 2
Task 1 completed in 1.82 seconds.
Starting task 5...
Got result from task 1: Result of task 1
Task 3 completed in 2.25 seconds.
Got result from task 3: Result of task 3
Task 4 completed in 1.45 seconds.
Got result from task 4: Result of task 4
Task 5 completed in 1.67 seconds.
Got result from task 5: Result of task 5
All tasks have been processed!

スレッドプールの利点

スレッドプールアプローチには、いくつかの利点があります。

  1. リソース管理: 同時に実行できるスレッドの数を制限し、システムのリソース枯渇を防ぎます。
  2. タスクスケジューリング(Task Scheduling): スレッドが利用可能になると、タスクのスケジューリングを自動的に処理し、新しいタスクを開始します。
  3. 結果の収集: 完了したタスクから結果を収集するための便利な方法を提供します。
  4. 例外処理: スレッドでの例外処理をより簡単に行えます。

この例では、max_workers=3 を設定しました。つまり、5 つのタスクがある場合でも、一度に 3 つのスレッドのみが実行されます。スレッドがタスクを完了すると、残りのタスクに再利用されます。

スレッドプールは、同時に実行するスレッドよりも多くのタスクがある場合、またはタスクが継続的に生成されている場合に特に役立ちます。

スレッドのタイムアウトとデーモンスレッド

この最終ステップでは、スレッド管理における 2 つの重要な概念、つまりタイムアウトの設定とデーモンスレッドの使用について学びます。これらのテクニックにより、スレッドの動作とメインプログラムとの対話をより詳細に制御できます。

スレッドのタイムアウトの操作

ステップ 2 で学習したように、join() メソッドはタイムアウトパラメータを受け入れます。これは、スレッドの完了を待ちたいが、特定の時点までのみ待機したい場合に役立ちます。

タイムアウトを使用してデータを取得しようとする関数を実装する、より実用的な例を作成しましょう。

  1. /home/labex/project ディレクトリに thread_with_timeout.py という名前の新しいファイルを作成します。

  2. 次のコードを追加します。

import threading
import time
import random

def fetch_data(data_id):
    """Simulate fetching data that might take varying amounts of time."""
    print(f"Fetching data #{data_id}...")

    ## Simulate different fetch times, occasionally very long
    fetch_time = random.choices([1, 8], weights=[0.8, 0.2])[0]
    time.sleep(fetch_time)

    if fetch_time > 5:  ## Simulate a slow fetch
        print(f"Data #{data_id}: Fetch took too long!")
        return None
    else:
        print(f"Data #{data_id}: Fetch completed in {fetch_time} seconds!")
        return f"Data content for #{data_id}"

def fetch_with_timeout(data_id, timeout=3):
    """Fetch data with a timeout."""
    result = [None]  ## Using a list to store result from the thread

    def target_func():
        result[0] = fetch_data(data_id)

    ## Create and start the thread
    thread = threading.Thread(target=target_func)
    thread.start()

    ## Wait for the thread with a timeout
    thread.join(timeout=timeout)

    if thread.is_alive():
        print(f"Data #{data_id}: Fetch timed out after {timeout} seconds!")
        return "TIMEOUT"
    else:
        return result[0]

## Try to fetch several pieces of data
for i in range(1, 6):
    print(f"\nAttempting to fetch data #{i}")
    result = fetch_with_timeout(i, timeout=3)
    if result == "TIMEOUT":
        print(f"Main thread: Fetch for data #{i} timed out, moving on...")
    elif result is None:
        print(f"Main thread: Fetch for data #{i} completed but returned no data.")
    else:
        print(f"Main thread: Successfully fetched: {result}")

print("\nAll fetch attempts completed!")
  1. ファイルを保存して実行します。
python3 /home/labex/project/thread_with_timeout.py

出力は異なりますが、次のようなものになるはずです。

Attempting to fetch data #1
Fetching data #1...
Data #1: Fetch completed in 1 seconds!
Main thread: Successfully fetched: Data content for #1

Attempting to fetch data #2
Fetching data #2...
Data #2: Fetch completed in 1 seconds!
Main thread: Successfully fetched: Data content for #2

Attempting to fetch data #3
Fetching data #3...
Data #3: Fetch timed out after 3 seconds!
Main thread: Fetch for data #3 timed out, moving on...
Data #3: Fetch took too long!

Attempting to fetch data #4
Fetching data #4...
Data #4: Fetch completed in 1 seconds!
Main thread: Successfully fetched: Data content for #4

Attempting to fetch data #5
Fetching data #5...
Data #5: Fetch completed in 1 seconds!
Main thread: Successfully fetched: Data content for #5

All fetch attempts completed!

この例は、以下を示しています。

  1. データを取得しようとし、時間がかかる可能性がある関数
  2. タイムアウトを使用するスレッド化されたラッパー関数
  3. タイムアウトを適切に処理し、他の操作を続行する方法

デーモンスレッドの理解

Python では、デーモンスレッドはバックグラウンドで実行されるスレッドです。デーモン(daemon)スレッドと非デーモン(non-daemon)スレッドの主な違いは、Python が終了する前にデーモンスレッドの完了を待たないことです。これは、プログラムの終了を妨げないバックグラウンドタスクを実行するスレッドに役立ちます。

デーモンスレッドを示す例を作成しましょう。

  1. /home/labex/project ディレクトリに daemon_threads.py という名前の新しいファイルを作成します。

  2. 次のコードを追加します。

import threading
import time

def background_task(name, interval):
    """A task that runs in the background at regular intervals."""
    count = 0
    while True:
        count += 1
        print(f"{name}: Iteration {count} at {time.strftime('%H:%M:%S')}")
        time.sleep(interval)

def main_task():
    """The main task that runs for a set amount of time."""
    print("Main task: Starting...")
    time.sleep(5)
    print("Main task: Completed!")

## Create two background threads
print("Creating background monitoring threads...")
monitor1 = threading.Thread(target=background_task, args=("Monitor-1", 1), daemon=True)
monitor2 = threading.Thread(target=background_task, args=("Monitor-2", 2), daemon=True)

## Start the background threads
monitor1.start()
monitor2.start()

print("Background monitors started, now starting main task...")

## Run the main task
main_task()

print("Main task completed, program will exit without waiting for daemon threads.")
print("Daemon threads will be terminated when the program exits.")
  1. ファイルを保存して実行します。
python3 /home/labex/project/daemon_threads.py

出力は次のようなものになるはずです。

Creating background monitoring threads...
Background monitors started, now starting main task...
Main task: Starting...
Monitor-1: Iteration 1 at 14:25:10
Monitor-2: Iteration 1 at 14:25:10
Monitor-1: Iteration 2 at 14:25:11
Monitor-1: Iteration 3 at 14:25:12
Monitor-2: Iteration 2 at 14:25:12
Monitor-1: Iteration 4 at 14:25:13
Monitor-1: Iteration 5 at 14:25:14
Monitor-2: Iteration 3 at 14:25:14
Main task: Completed!
Main task completed, program will exit without waiting for daemon threads.
Daemon threads will be terminated when the program exits.

この例では、次のことが行われました。

  1. 定期的にメッセージを出力する、継続的に実行される 2 つのデーモンスレッドを作成しました。
  2. スレッドを作成するときに daemon=True を設定し、それらをデーモンスレッドとしてマークしました。
  3. メインスレッドは 5 秒間実行され、その後終了します。
  4. メインスレッドが終了すると、プログラムが終了し、デーモンスレッドも自動的に終了します。

非デーモン vs. デーモンスレッド

違いをよりよく理解するために、デーモンスレッドと非デーモンスレッドを比較するもう 1 つの例を作成しましょう。

  1. /home/labex/project ディレクトリに daemon_comparison.py という名前の新しいファイルを作成します。

  2. 次のコードを追加します。

import threading
import time

def task(name, seconds, daemon=False):
    """A task that runs for a specified amount of time."""
    print(f"{name} starting {'(daemon)' if daemon else '(non-daemon)'}")
    time.sleep(seconds)
    print(f"{name} finished after {seconds} seconds")

## Create a non-daemon thread that runs for 8 seconds
non_daemon_thread = threading.Thread(
    target=task,
    args=("Non-daemon thread", 8, False),
    daemon=False  ## This is the default, so it's not actually needed
)

## Create a daemon thread that runs for 8 seconds
daemon_thread = threading.Thread(
    target=task,
    args=("Daemon thread", 8, True),
    daemon=True
)

## Start both threads
non_daemon_thread.start()
daemon_thread.start()

## Let the main thread run for 3 seconds
print("Main thread will run for 3 seconds...")
time.sleep(3)

## Check which threads are still running
print("\nAfter 3 seconds:")
print(f"Daemon thread is alive: {daemon_thread.is_alive()}")
print(f"Non-daemon thread is alive: {non_daemon_thread.is_alive()}")

print("\nMain thread is finishing. Here's what will happen:")
print("1. The program will wait for all non-daemon threads to complete")
print("2. Daemon threads will be terminated when the program exits")

print("\nWaiting for non-daemon threads to finish...")
## We don't need to join the non-daemon thread, Python will wait for it
## But we'll explicitly join it for clarity
non_daemon_thread.join()
print("All non-daemon threads have finished, program will exit now.")
  1. ファイルを保存して実行します。
python3 /home/labex/project/daemon_comparison.py

出力は次のようになります。

Non-daemon thread starting (non-daemon)
Daemon thread starting (daemon)
Main thread will run for 3 seconds...

After 3 seconds:
Daemon thread is alive: True
Non-daemon thread is alive: True

Main thread is finishing. Here's what will happen:
1. The program will wait for all non-daemon threads to complete
2. Daemon threads will be terminated when the program exits

Waiting for non-daemon threads to finish...
Non-daemon thread finished after 8 seconds
All non-daemon threads have finished, program will exit now.

主な観察事項:

  1. 両方のスレッドが開始され、同時に実行されます。
  2. 3 秒後、両方のスレッドはまだ実行されています。
  3. プログラムは、非デーモンスレッドが完了するのを待ちます(8 秒後)。
  4. プログラムが終了すると、デーモンスレッドはまだ実行されていますが、終了します。
  5. プログラムが終了すると、デーモンスレッドは終了するため、完了メッセージが出力されることはありません。

デーモンスレッドを使用する場合

デーモンスレッドは、以下に役立ちます。

  • バックグラウンド監視タスク
  • クリーンアップ操作
  • プログラムの実行中に実行する必要があるが、プログラムの終了を妨げないサービス
  • 定期的にイベントをトリガーするタイマースレッド

非デーモンスレッドは、以下に適しています。

  • 完了する必要がある重要な操作
  • 中断してはならないタスク
  • プログラムが終了する前に正常に完了する必要がある操作

各タイプを使用するタイミングを理解することは、堅牢なマルチスレッドアプリケーションを設計する上で重要な部分です。

まとめ

この実験(Lab)では、Python のスレッドを操作するための基本的なテクニックと、それらの完了を待つ方法について学びました。以下に、カバーされた主要な概念の概要を示します。

  1. スレッドの作成と開始: スレッドオブジェクトを作成し、ターゲット関数を指定し、start() メソッドでその実行を開始する方法を学びました。

  2. join() を使用したスレッドの待機: メインプログラムを続行する前に、スレッドが完了するのを待つために join() メソッドを使用する方法を発見し、適切な同期を確保しました。

  3. 複数のスレッドの操作: 複数のスレッドを手動で作成および管理し、より効率的なスレッド管理のために ThreadPoolExecutor クラスを使用する練習をしました。

  4. スレッドのタイムアウトとデーモンスレッド: スレッド操作のタイムアウトの設定や、バックグラウンドタスクにデーモンスレッドを使用するなど、高度なトピックを探求しました。

これらのスキルは、Python でマルチスレッドアプリケーションを開発するための基盤を提供します。マルチスレッド化により、プログラムは複数のタスクを同時に実行できるようになり、パフォーマンスと応答性が向上します。特に、I/O バウンド操作の場合に効果的です。

スレッドを使い続ける際には、次のベストプラクティスを覚えておいてください。

  • CPU バウンドタスクではなく、I/O バウンドタスクにスレッドを使用する(後者の場合は、マルチプロセッシングの使用を検討してください)
  • 共有リソースに注意し、適切な同期メカニズムを使用する
  • 複数のスレッドを管理するために、ThreadPoolExecutor のようなより高レベルの抽象化を使用することを検討する
  • プログラムの終了を妨げないバックグラウンドタスクにデーモンスレッドを使用する

これらのスキルと実践により、マルチスレッド化技術を使用して、より効率的で応答性の高い Python アプリケーションを構築できるようになりました。