Привет всем! Сегодня — небольшой пост, посвященный вопросу «Работа с потоками в Python». Ну и конечно — пример кода для работы с потоками 🙂 Надеюсь — будет полезно.
Итак, что такое потоки в Python? Python использует потоки для реализации многозадачности. Потоки позволяют запускать несколько команд или задач одновременно и манипулировать ими, не останавливая выполнение других задач. ЗАчем это нужно? Ну, например — это может быть полезно, при работе с сетью или многомерными данными, где необходимо выполнять несколько операций одновременно и обрабатывать результаты параллельно.
Теперь пример работы с потоками. Будем выводить результат вычислений числа Фибоначчи (можно что-то другое, но сейчас в голову не приходит ничего больше из того, что может заставить компьютер сильно задуматься). Естественно — мы будем смотреть на время, в течении которого выполняется код. Для этого и нужна библиотека time. Итак, вывод числа Фибоначчи для, например, числа 40:
import time def fibonacci(n): if n <= 0: return 0 elif n == 1: return 1 else: return fibonacci(n - 1) + fibonacci(n - 2) start = time.time() print('Результат: ', fibonacci(40)) end = time.time() result = end - start print('Начало работы: ', start) print('Конец работы: ', end) print('Код работал: ', result, 'секунд')
Получаем результат:
Результат: 102334155 Начало работы: 1674906951.9962122 Конец работы: 1674907029.9873629 Код работал: 77.99115061759949 секунд
Это для понимания того, что задача ого-го какая ресурсоемкая для компьютера…
Ок, а теперь изменим код так, что бы он считал числа Фибоначчи в промежутке от 1 до 30:
import time def fibonacci(n): if n <= 0: return 0 elif n == 1: return 1 else: return fibonacci(n - 1) + fibonacci(n - 2) start = time.time() for i in range(1, 31): print('Для числа', i, ':', fibonacci(i)) # print('результат: ', fibonacci(i)) end = time.time() result = end - start print('Код работал ', result, 'секунд')
После чего получаем результат:
Для числа 1 : 1 Для числа 2 : 1 Для числа 3 : 2 Для числа 4 : 3 Для числа 5 : 5 Для числа 6 : 8 Для числа 7 : 13 Для числа 8 : 21 Для числа 9 : 34 Для числа 10 : 55 Для числа 11 : 89 Для числа 12 : 144 Для числа 13 : 233 Для числа 14 : 377 Для числа 15 : 610 Для числа 16 : 987 Для числа 17 : 1597 Для числа 18 : 2584 Для числа 19 : 4181 Для числа 20 : 6765 Для числа 21 : 10946 Для числа 22 : 17711 Для числа 23 : 28657 Для числа 24 : 46368 Для числа 25 : 75025 Для числа 26 : 121393 Для числа 27 : 196418 Для числа 28 : 317811 Для числа 29 : 514229 Для числа 30 : 832040 Код работал 1.2446682453155518 секунд
Прекрасно! А теперь представим, что нам нужно (кто его знает, зачем, но нужно) — считать числа Фибоначчи одновременно. Если мы запустим выполнение задачи в цикле (например, 10 раз подряд) — т.е. считаем числа от 1 до 30 первый раз — то тратим 1,24 секунд. Считаем второй раз — опять 1,24 секунд. Каждый следующий проход увеличивает время на те же самые плюс-минус 1,24 секунд.
Посмотрите на код, который демонстрирует данную возможность:
import time def fibonacci(n): if n <= 0: return 0 elif n == 1: return 1 else: return fibonacci(n - 1) + fibonacci(n - 2) start = time.time() for x in range(1, 11): print('Проход: ', x) for i in range(1, 31): print('Для числа', i, ':', fibonacci(i)) end = time.time() result = end - start print('Код работал ', result, 'секунд')
И теперь результат:
Код работал 14.41745662689209 секунд
А что, если начать использовать потоки?
Давайте попробуем (комментарии к коду — внутри):
#Импортируем модули threading и time, которые будем использовать для создания и запуска потоков, а так #же для измерения времени выполнения. import threading import time #Эта функция вычисляет число Фибоначчи для данного индекса n. def fibonacci(n): if n <= 0: return 0 elif n == 1: return 1 else: return fibonacci(n - 1) + fibonacci(n - 2) #Эта функция будет исполняться в каждом потоке. Выводит сообщение о том, что поток работает, затем #использует функцию fibonacci() для вычисления и вывода чисел Фибоначчи для индексов от 1 до 30. def thread_func(i): print(f'Поток {i} работает...') for i in range(1, 31): print('Для числа', i, ':', fibonacci(i)) #Запоминаем время начала работы start = time.time() #Создаем 10 потоков, каждый из которых будет исполнять функцию thread_func. Эта функция печатает #сообщение о том, что поток работает, а затем исполняет цикл от 1 до 30 и для каждого числа вызывает #функцию fibonacci, которая находит числа Фибоначчи для этого числа и выводит результат на экран. После #создания всех потоков, программа засекает время и выводит начальное и конечное время, а также разницу #между ними, чтобы определить, сколько времени заняла работа программы. threads = [] for i in range(10): t = threading.Thread(target=thread_func, args=(i,)) threads.append(t) t.start() for thread in threads: thread.join() end = time.time() result = end - start print('Начало: ', start) print('Конец: ', end) print('Код работал ', result, 'секунд')
Итак, код с потоками имеется, и он — после выполнения — показывает следующие результаты работы программы:
Код работал 12.041714906692505 секунд
что на 2 секунды быстрее, если бы мы повторяли цикл раз за разом (напомню, что выполнение одного цикла у нас занимало 14 с копейками секунд.
Вот… надеюсь, вам стало немного проще разобраться с потоками в Python и как с ними работать. Как всегда — в случае возникновения вопросов пишите в Telegram или на почту 😉