Начнем с определения потока, поток - это не что иное, как легкий процесс. Они обычно присутствуют внутри процесса и совместно используют память и состояние процесса. Таким образом, в многопоточности мы можем выполнять несколько потоков одновременно.

Но вот и идет GIL, здесь мы не будем это подробно обсуждать. Но, попросту говоря, GIL позволяет одновременно запускать только один поток. Теперь вы, должно быть, думаете, что в таком случае многопоточность, когда мы можем запускать только один поток за раз?

Итак, прежде чем ответить на вышеуказанный вопрос, мы должны понять, что задача, которую мы выполняем в системе, бывает двух типов: с привязкой к ЦП или с привязкой к вводу-выводу. например, умножение больших матриц ограничено ЦП, но запрос веб-страницы с веб-сервера ограничен вводом-выводом. Многопоточность в Python полезна при выполнении задач, связанных с вводом-выводом. В задачах с привязкой к ЦП GIL не снимает блокировку до тех пор, пока задача не будет завершена, но в задаче с привязкой к вводу-выводу, как только потоки запускаются из-за ожидания некоторого ввода-вывода, GIL может снять свою блокировку.

Приведенный ниже код демонстрирует возможности многопоточности в задаче с привязкой к вводу-выводу.

import datetime
import threading

import requests


def io_bound_task(url):
    resp = requests.get(url)
    print("Received Response", resp.status_code)


def sequential(url):
    # call the function sequentially 5 times.
    start_time = datetime.datetime.now()
    for i in range(5):
        io_bound_task(url)
    time_elapsed = datetime.datetime.now() - start_time
    print("Time Elapsed using normal sequential method", time_elapsed)
    return time_elapsed


def threader(url):
    # call the function in 5 separate threads.
    threads = []
    start_time = datetime.datetime.now()
    for i in range(5):
        # Create a new thread, assign it the worker function, and the argument for it
        p = threading.Thread(target=io_bound_task, args=(url,))
        p.start()  # Start the thread
        threads.append(p)  # Add it to list of threads
    for thread in threads:
        thread.join()  # wait for all the threads to finish
    time_elapsed = datetime.datetime.now() - start_time
    print("Time Elapsed using multi threading", time_elapsed)
    return time_elapsed


if __name__ == "__main__":
    url = "https://www.spotify.com"
    normal_time = sequential(url)
    threading_time = threader(url)
    print("Improvement percent", int((normal_time - threading_time) / normal_time * 100))



# Improvement percent 87
# Process finished with exit code 0

Как видите, мы видим значительное улучшение в многопоточной версии.

Теперь обратитесь к следующему примеру выполнения задачи, связанной с процессором.

import datetime
import threading

import requests


def cpu_bound_task(number):
    sum = 0
    for i in range(number):
        sum += i
    print(sum)
    return sum


def sequential(number):
    # call the function sequentially 5 times.
    start_time = datetime.datetime.now()
    for i in range(5):
        cpu_bound_task(number)
    time_elapsed = datetime.datetime.now() - start_time
    print("Time Elapsed using normal sequential method", time_elapsed)
    return time_elapsed


def threader(number):
    # call the function in 5 separate threads.
    threads = []
    start_time = datetime.datetime.now()
    for i in range(5):
        # Create a new thread, assign it the worker function, and the argument for it
        p = threading.Thread(target=cpu_bound_task, args=(number,))
        p.start()  # Start the thread
        threads.append(p)  # Add it to list of threads
    for thread in threads:
        thread.join()  # wait for all the threads to finish
    time_elapsed = datetime.datetime.now() - start_time
    print("Time Elapsed using multi threading", time_elapsed)
    return time_elapsed


if __name__ == "__main__":
    number = 50000000
    normal_time = sequential(number)
    threading_time = threader(number)
    print("Improvement percent", int((normal_time - threading_time) / normal_time * 100))

# Improvement percent 7

Итак, я надеюсь, что теперь вы получили общее представление о том, когда многопоточность полезна.

* Примечание. В этом блоге не подробно рассказывается о том, как работает GIL, это скорее руководство для начинающих по многопоточности и ее использованию.

Пожалуйста, поделитесь своими комментариями, приветствиями и приятным обучением. Прощай.