Как сделать несколько программ в одном проекте python

Python включает в себя ряд разных параллельных конструкций, таких как как threading, queues и multiprocessing. Модуль threading использовался как главный способ достижения параллельности. Несколько лет назад, модуль multiprocessing был добавлен в пакет стандартных библиотек Python. В этой статье мы сфокусируемся на том, как использовать очереди и потоки (queues и threads).

Использование потоков

Как сделать несколько программ в одном проекте python

В приведенном выше примере создается функция, которая запускается в отдельных потоках. Эта функция запускает поток, а затем засыпает, имитируя некоторое внешнее время ожидания.

В функции main видно, как реализованы оба метода:

  • первый в строках 9-19.
  • второй в строках 23-24.

from concurrent.futures import ThreadPoolExecutor import logging import time import urllib.request as url_request def main(): collected_data = list() urls = [ «https://python.org», «https://docs.python.org/», «https://wikipedia.org», «https://imdb.com», «https://google.com» ] logging.info(f»************** Starting threads ****************») with ThreadPoolExecutor(max_workers=5) as executor: for url in urls: executor.submit(thread_function, url, collected_data) for data_stream in collected_data: logging.info(f»First part of data stream for : «) logging.info(f»————————————————————————————-«) logging.info(f»******************************************************») def thread_function(url, collected_data): connection = url_request.urlopen(url) data_stream = connection.read() collected_data.append() if __name__ == «__main__»: # Setting a logger to track the progress logging.basicConfig(format=»%(message)s», level=logging.INFO) s = time.perf_counter() main() elapsed = time.perf_counter() — s logging.info(f» executed in seconds.»)

В этом куске кода использована многопоточность для одновременного чтения данных из нескольких URL-адресов, выполнения нескольких экземпляров thread_function() и сохранения результатов в списке.

Разбиваем проект на файлы

Как видно из примера, ThreadPoolExecutor упрощает обработку необходимых потоков. Хотя это простой пример, возможно отправить больше URL-адресов, используя ThreadPoolExecutor не дожидаясь каждого ответа.

Из приведенных выше примеров видно, что потоки — это удобный и понятный способ обработки задач, ожидающих других ресурсов. Также видно, что стандартная библиотека Python поставляется с высокоуровневыми реализациями, которые еще больше упрощают эту задачу.

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека питониста»

Coroutines и asyncio

Coroutines (сопрограммы) – альтернативный способ одновременного выполнения функции посредством специальных конструкций, а не системных потоков.

Прекрати писать код в ОДНОМ файле Python | ТОП 5 Ошибок и создание правильной архитектуры

Сопрограмма – общая структура управления, в которой управление потоком совместно передается между двумя подпрограммами без возврата. Получаем однопоточную однопроцессорную конструкцию, использующую кооперативную многозадачность.

В то время, как многопоточность берет и запускает функции в отдельных потоках, asyncio работает в одном потоке и разрешает циклу обработки событий программы взаимодействовать с несколькими задачами, чтобы каждая из них выполнялась по очереди в оптимальное время.

Реализуем это на Python с помощью библиотеки asyncio , предоставляющей основу и API для запуска и управления сопрограммами с ключевыми словами async и await .

import asyncio import logging import time async def async_function(number): logging.info(f»Starting Async function: «) await asyncio.sleep(1) logging.info(f»Finishing Async function: «) async def main(): logging.info(«************ Starting Async Program ***************») await asyncio.gather(async_function(1), async_function(2), async_function(3)) logging.info(«***************************************************») if __name__ == «__main__»: logging.basicConfig(format=»%(message)s», level=logging.INFO) s = time.perf_counter() asyncio.run(main()) elapsed = time.perf_counter() — s print(f» executed in seconds.»)
import asyncio import sys from aiohttp import ClientSession import logging import time async def async_function(session, url): async with session.get(url) as request: data_stream = await request.text() return async def main(): urls = [ «https://python.org», «https://docs.python.org/», «https://wikipedia.org», «https://imdb.com», «https://google.com» ] logging.info(«************ Starting Async Program ***************») async with ClientSession() as session: collected_data = await asyncio.gather(*[async_function(session, _) for _ in urls]) for data_stream in collected_data: logging.info(f»First part of data stream for : «) logging.info(f»————————————————————————————-«) logging.info(«***************************************************») if __name__ == «__main__»: logging.basicConfig(format=»%(message)s», level=logging.INFO) s = time.perf_counter() if sys.version_info[:2] == (3, 7): asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) loop = asyncio.get_event_loop() try: loop.run_until_complete(main()) loop.run_until_complete(asyncio.sleep(2.0)) finally: loop.close() #asyncio.run(main()) elapsed = time.perf_counter() — s logging.info(f» executed in seconds.»)

Читайте также:
Как выглядит программа 1с предприятие

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

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

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

Многопроцессорность

Многопроцессорность – механизм, разрешающий параллельно выполнять ресурсоемкие задачи, запуская независимые экземпляры интерпретатора Python.

Каждый экземпляр получает код и данные, необходимые для выполнения рассматриваемой задачи, и выполняется независимо в собственном потоке.

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

from multiprocessing import Pool import time import logging def main(): logging.info(f»************** Starting Multiprocessing ****************») with Pool() as p: p.map(processing_function, range(3)) logging.info(f»********************************************************») def processing_function(name): logging.info(f»Process starting: «) time.sleep(5) logging.info(f»Process finishing: «) if __name__ == «__main__»: # Setting a logger to track the progress logging.basicConfig(format=»%(message)s», level=logging.INFO) s = time.perf_counter() main() elapsed = time.perf_counter() — s logging.info(f» executed in seconds.»)

Пример выше показывает многопроцессорную обработку, а ниже та же функциональность чтения данных с несколькими URL одновременно.

from multiprocessing import Pool import time import logging import urllib.request as url_request def main(): urls = [ «https://python.org», «https://docs.python.org/», «https://wikipedia.org», «https://imdb.com», «https://google.com» ] logging.info(f»************** Starting Multiprocessing ****************») with Pool() as p: collected_data = p.map(request_function, urls) for data_stream in collected_data: logging.info(f»First part of data stream for : «) logging.info(f»————————————————————————————-«) logging.info(f»********************************************************») def request_function(url): connection = url_request.urlopen(url) data_stream = str(connection.read()) return if __name__ == «__main__»: # Setting a logger to track the progress logging.basicConfig(format=»%(message)s», level=logging.INFO) s = time.perf_counter() main() elapsed = time.perf_counter() — s logging.info(f» executed in seconds.»)

В фрагменте выше объект Pool() представляет повторно используемую группу процессов, которая сопоставляет итерации для распределения между каждым экземпляром функции.

Преимущество: каждая операция выполняется в отдельной среде выполнения Python и на полном ядре ЦП, что разрешает одновременно запускать процессы интенсивно использующие ЦП.

Недостаток: каждый подпроцесс требует копию данных (с которой подпроцесс работает), отправленных из главного процесса и, как правило, возвращающих данные в главный процесс.

В статье были рассмотрены концепции:

И подходы для работы с этими концепциями:

  • Многопоточность.
  • Coroutines и asyncio.
  • Многопроцессорность.

Материалы по теме

  • Что такое yield в Python? Самый популярный вопрос на Стаковерфлоу по Питону
  • Фундаментальные структуры данных: массивы и связанные списки с реализацией на Python
  • Вопрос века: какие кавычки использовать в Python – одинарные или двойные?
Читайте также:
Кто пишет программы для компьютера профессия

Источник: proglib.io

Многопоточность в Python: справочник

Многопоточность в Python — это способ достижения многозадачности в Python с использованием концепции потоков.

Multithreading питон

Что такое поток?

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

Каковы преимущества многопоточности в Python?

У создания многопоточных приложений есть немало преимуществ. Давайте посмотрим на некоторые преимущества:

  • Эффективное использование ресурсов;
  • Более отзывчивый;
  • Совместное использование ресурсов делает его более экономичным;
  • Эффективное использование многопроцессорной архитектуры за счет параллелизма;
  • Экономит время;
  • Потоки (поскольку они являются частью одного процесса) легче взаимодействуют друг с другом, чем если бы они были отдельными процессами;
  • Они не требуют больших затрат памяти;
  • Многопоточные серверы и интерактивные графические интерфейсы используют исключительно многопоточность.

Многопоточность используется случаях:

  1. Когда выходы подпрограмм нужно объединить с основной программой.
  2. Если основная программа содержит фрагмент кода, который относительно независим друг от друга.
  3. Когда выходы подпрограмм нужно объединить с основной программой.
  4. Основная программа содержит фрагмент кода, который относительно независим друг от друга.

Модуль Threading определяет множество функций, которые используются для получения данных, связанных с потоками, и эти функции выполняются автоматически.

Эта функция возвращает количество объектов Thread, которые в данный момент живы. Здесь возвращаемое количество равно длине списка, возвращаемого enumerate().

Эта функция возвращает текущий объект Thread, и он соответствует потоку управления вызывающей стороны.

Эта функция возвращает «идентификатор потока» текущего потока. Это ненулевое целое число.

Эта функция возвращает список всех текущих объектов Thread, включая демонические потоки, функция current_thread() создает фиктивный поток и основной поток и исключает завершенные потоки и потоки, которые еще не были запущены.

Эта функция возвращает основной объект Thread.

Когда все потоки запускаются из модуля потоков, установите функцию трассировки. Перед вызовом метода run() эта функция передается в sys.settrace() для каждого потока.

Когда все потоки запускаются из модуля потоков, установите функцию профиля. Перед вызовом метода run() эта функция передается в sys.setprofile() для каждого потока.

Эта функция возвращает размер стека потоков и используется при создании новых потоков.

import threading def trace_function(): print(«Passing the trace function») def profile(): print(«PROFILE THREAD: » + str(threading.current_thread().getName())) class mythread(threading.Thread): def __init__(self, thread_name, thread_ID): threading.Thread.__init__(self) self.thread_name = thread_name self.thread_ID = thread_ID def run(self): print(str(self.thread_ID)); print(«ACTIVE THREADS ARE: «+ str(threading.active_count())) print(«CURRENT THREAD IS: » + str(threading.current_thread().getName())) my_thread1 = mythread(«PP», 500) my_thread2 = mythread(«PythonProgram», 1000); print(«NAME OF THE MAIN THREAD: » + str(threading.main_thread().getName())) print(«IDENTIFICATION OF MAIN THREAD: «+ str(threading.get_ident())) print(«STACK SIZE = » + str(threading.stack_size())) print(threading.settrace(trace_function())) threading.setprofile(profile()) my_thread1.start() my_thread2.start() print(«LIST OF ENUMERATION: «) print(threading.enumerate()) print(«EXIT»)

Эта константа имеет максимальное значение, допустимое для параметра времени ожидания функций блокировки (Lock.acquire(), RLock.acquire(), Condition.wait() и т. д.).

NAME OF THE MAIN THREAD: MainThread IDENTIFICATION OF MAIN THREAD: 5436 STACK SIZE = 0 Passing the trace function None PROFILE THREAD: MainThread 500 1000LIST OF ENUMERATION: ACTIVE THREADS ARE: 6 [<_MainThread(MainThread, started 5436)>, , , , , ] EXIT CURRENT THREAD IS: Thread-8 ACTIVE THREADS ARE: 5 CURRENT THREAD IS: Thread-9

Перейдем к созданию нашего первого многопоточного приложения.

1. Импортируйте модуль потоковой передачи.

Для создания потока мы будем использовать модуль threading .

Читайте также:
Эта программа заблокирована групповой политикой код ошибки 0x800704ec

import threading

Модуль threading передачи состоит из класса Thread который создается для создания потока.

Поток может быть создан путем создания объекта класса Thread. Аргументы для этого класса следующие:

  1. target: здесь указывается функция, которая будет вызываться потоком. Эта функция представляет собой вызываемый объект, вызываемый методом run() потока.
  2. args: Здесь мы указываем аргументы target функции.

def print_hi(num): print(«Hi, you are customer «,num) t1 = threading.Thread(target=print_square, args=(10,))

Приведенный выше фрагмент кода вызывает print_hi() вызываемую как target параметр. У этой функции есть один параметр, а именно num который указывается с помощью args .

Иллюстрация Основного Потока и Дочерних

2. Запуск

Поток запускается путем вызова метода start() модуля threading передачи объекта Thread.

t1.start()

Он должен вызываться не более одного раза для каждого объекта потока. Он организует вызов метода run() объекта в отдельном потоке управления.

Этот метод вызовет RuntimeError если будет вызван более одного раза для одного и того же объекта потока.

Поток вызывается в программе, которая сама по себе является процессом. Таким образом, во время выполнения потока основная программа также продолжает свое выполнение.

Следовательно, мы можем приостановить деятельность основной программы (выполняемой основным потоком) до завершения созданного потока.

3. Метод соединения Thread

def print_hi(num): print(«Hi, you are customer «,num) t1 = threading.Thread(target = print_hi, args=(10,)) t1.start() t1.join() print(«End»)

В приведенном выше фрагменте для создания объекта используется класс Thread которому присвоено имя t1. Метод start() вызывается для объекта потока t1, который отмечает начало активности потока.

Затем вызывается метод join() . Таким образом мы гарантируем, что основная программа остановит выполнение основного потока и дождется завершения потока t1. Как только t1 завершит свою работу, основной поток (основная программа) может продолжить свое выполнение. Следовательно, print(«End») строки print(«End») выполняется только после завершения активности потока.

Hi, you are customer 10 End

Без использования метода join() у интерпретатора есть выбор между двумя операторами печати — print(«Hi, you are customer «, num) и print(«End») . В таких сценариях невозможно предсказать, какой оператор печати будет отображаться первым, потому что выполнение этих строк выбирается интерпретатором.

4. Синхронизация потоков в Python

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

Необходимо убедиться, что два потока не обращаются к этому ресурсу одновременно, поскольку это может привести к состоянию гонки.

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

Следовательно, мы используем блокировки в программе, которые временно останавливают выполнение программы до тех пор, пока блокировка не будет снята. Это делается для того, чтобы два потока не обращались к одной и той же переменной и не вызывали конфликтов.

Недостатки многопоточности

  • Увеличивает сложность программы;
  • Необходима синхронизация общих ресурсов (объектов, данных);
  • Сложно отлаживать непредсказуемые результаты;
  • Создание и синхронизация потоков требует больших затрат ресурсов ЦП и памяти.

Источник: pythononline.ru

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru