Потоки в Python. Модуль threading

Потоки в Python. Модуль threading

Потоки в Python используются для того чтобы отделить какие-то затяжные по времени функции от основной программы, чтобы во время их выполнения, программа продолжала работать. Можно создавать несколько потоков одновременно, и запускать их параллельно. Для работы с потоками чаще всего используется модуль threading. Давайте напишем программу, которая будет скачивать файлы из интернета в несколько потоков, количество которых соответствует количеству файлов.

# Подключаем модуль threading для работы с потоками
import threading
# и модули requests, shutil, os для скачивания файлов из сети
import requests, shutil, os

# Функция скачивания файла которую мы будем выполнять
# в новом потоке на входе номер потока и URL скачиваемого файла
def down(nomer, url):
    # Выводим на экран сообщение о старте нового потока
    print(str(nomer)+' поток ('+url+')\n')
    # Получаем имя файла из URL
    (dirname, filename) = os.path.split(url)
    # Запускаем скачивание через GET запрос
    r = requests.get(url, stream=True)
    # Если код ответа сервера 200 (сервер доступен)
    if r.status_code == 200:
        # Открываем файл в режиме побайтовой записи
        with open(filename, 'wb') as f:
            r.raw.decode_content = True
            # Созхраняем скачиваемый поток в файл
            shutil.copyfileobj(r.raw, f)
        # Выводим сообщение что поток закончил загрузку
        print(str(nomer) + " поток закончил загрузку\n")
        

# Список URL которые будем скачивать
urls = ["http://www.irs.gov/pub/irs-pdf/f1040.pdf",
            "http://www.irs.gov/pub/irs-pdf/f1040a.pdf",
            "http://www.irs.gov/pub/irs-pdf/f1040ez.pdf",
            "http://www.irs.gov/pub/irs-pdf/f1040es.pdf",
            "http://www.irs.gov/pub/irs-pdf/f1040sb.pdf"]

# Цикл который создаст столько потоков сколько файлов нужно скачать
for nomer, url in enumerate(urls):
    # Запускаем поток указав целью функцию down и ее аргументы
    # к nomer прибавляем 1 чтобы номер потока начинался не с нуля
    threading.Thread(target=down, args = [nomer+1, url]).start()

# Выводим сообщение демонстрирующее что основная программа
# продолжает работать отдельно от созданных потоков
print('\nЕще не завершились потоки а программа уже продолжается\n')
Как видим, потоки завершаются не в том порядке в котором их запускали, а независимо друг от друга. Основная программа также продолжает работу, не дожидаясь окончания работы всех потоков. Чтобы упростить создание потоков-функций можно сделать заготовку:
# Импортируем модуль threading для работы с потоками
import threading

# Отдельная функция-заготовка для вынесения 
# последующих функций в отдельный поток
def thread(my_func):
    def wrapper(*args, **kwargs):
        my_thread = threading.Thread(target=my_func, args=args, kwargs=kwargs)
        my_thread.start()
    return wrapper

# Теперь чтобы запустить любую функцию в отдельный поток
# достаточно над ее именем написать @thread
@thread
def go(nomer):
    # В этой функции будем печатать числа от 1 до 199
    for x in range(1, 200):
        print('Поток номер '+str(nomer)+' число '+str(x)+'\n')

# Запускаем функцию три раза и получаем три потока 
go(1)
go(2)
go(3)
Мы описали функцию-заготовку для создания потока и назвали ее thread. Теперь, если мы будем писать перед любой функцией строчку @thread то эта функция станет выполняться в отдельном потоке. Это очень удобно. Всего лишь @thread над именем функции и вот она уже исполняется в новом потоке. Исходники данных примеров можно скачать здесь

Потоки в Python. Модуль threading Лого Pythono.ru Потоки в Python. Модуль threading