Я выполняю вложенный цикл в python, который приведен ниже. Это служит основным способом поиска по существующим финансовым временным рядам и поискам периодов в временных рядах, которые соответствуют определенным характеристикам. В этом случае существуют два отдельных массива одинакового размера, представляющие «близкие» (например, стоимость актива) и «объем» (т.е.
Объем актива, который был обменен за период). Для каждого периода времени я хотел бы смотреть на все будущие интервалы с длинами от 1 до INTERVAL_LENGTH и посмотреть, соответствуют ли какие-либо из этих интервалов характеристикам, которые соответствуют моему поиску (в этом случае отношение значений закрытия больше 1,0001 и менее чем 1,5, а суммарный объем больше 100). Я понимаю, что одной из основных причин ускорения при использовании NumPy является то, что интерпретатору не нужно вводить проверки операндов каждый раз, когда он что-то оценивает, пока вы работаете в массиве в целом (например, numpy_array * 2), но, очевидно, код ниже не использует это. Есть ли способ заменить внутренний цикл на какую-то функцию окна, которая может привести к ускорению или любому другому способу, использующему numpy/scipy, чтобы ускорить это по существу на родном питоне? Альтернативно, есть ли лучший способ сделать это вообще (например, будет ли намного быстрее писать этот цикл на С++ и использовать переплетение)?
ТОП способов Ускорить Код Python. На примере построения Фрактала Мандельброта в Pygame
ARRAY_LENGTH = 500000 INTERVAL_LENGTH = 15 close = np.array( xrange(ARRAY_LENGTH) ) volume = np.array( xrange(ARRAY_LENGTH) ) close, volume = close.astype(‘float64’), volume.astype(‘float64’) results = [] for i in xrange(len(close) — INTERVAL_LENGTH): for j in xrange(i+1, i+INTERVAL_LENGTH): ret = close[j] / close[i] vol = sum( volume[i+1:j+1] ) if ret > 1.0001 and ret < 1.5 and vol >100: results.append( [i, j, ret, vol] ) print results
erich 17 июнь 2010, в 23:22
Поделиться
Ваш расчет выглядит очень просто, почему бы вам не использовать Cython?
Tarantula 17 июнь 2010, в 21:19
Поделиться:
3 ответа
Лучший ответ
Обновление: (почти) полностью векторизованная версия ниже в «new_function2».
Я добавлю комментарии, чтобы немного объяснить это.
Это дает 50-кратное ускорение, и более быстрое ускорение возможно, если вы в порядке с выходом, состоящим из массивов numpy вместо списков. Как есть:
In [86]: %timeit new_function2(close, volume, INTERVAL_LENGTH) 1 loops, best of 3: 1.15 s per loop
Вы можете заменить свой внутренний цикл на вызов np.cumsum(). См. мою функцию «new_function» ниже. Это дает значительное ускорение.
In [61]: %timeit new_function(close, volume, INTERVAL_LENGTH) 1 loops, best of 3: 15.7 s per loop
In [62]: %timeit old_function(close, volume, INTERVAL_LENGTH) 1 loops, best of 3: 53.1 s per loop
Должна быть возможность векторизовать всю вещь и полностью избегать циклов, хотя. Дайте мне минуту, и я увижу, что я могу сделать.
import numpy as np ARRAY_LENGTH = 500000 INTERVAL_LENGTH = 15 close = np.arange(ARRAY_LENGTH, dtype=np.float) volume = np.arange(ARRAY_LENGTH, dtype=np.float) def old_function(close, volume, INTERVAL_LENGTH): results = [] for i in xrange(len(close) — INTERVAL_LENGTH): for j in xrange(i+1, i+INTERVAL_LENGTH): ret = close[j] / close[i] vol = sum( volume[i+1:j+1] ) if (ret > 1.0001) and (ret < 1.5) and (vol >100): results.append( (i, j, ret, vol) ) return results def new_function(close, volume, INTERVAL_LENGTH): results = [] for i in xrange(close.size — INTERVAL_LENGTH): vol = volume[i+1:i+INTERVAL_LENGTH].cumsum() ret = close[i+1:i+INTERVAL_LENGTH] / close[i] filter = (ret > 1.0001) 1.5) 100) j = np.arange(i+1, i+INTERVAL_LENGTH)[filter] tmp_results = zip(j.size * [i], j, ret[filter], vol[filter]) results.extend(tmp_results) return results def new_function2(close, volume, INTERVAL_LENGTH): vol, ret = [], [] I, J = [], [] for k in xrange(1, INTERVAL_LENGTH): start = k end = volume.size — INTERVAL_LENGTH + k vol.append(volume[start:end]) ret.append(close[start:end]) J.append(np.arange(start, end)) I.append(np.arange(volume.size — INTERVAL_LENGTH)) vol = np.vstack(vol) ret = np.vstack(ret) J = np.vstack(J) I = np.vstack(I) vol = vol.cumsum(axis=0) ret = ret / close[:-INTERVAL_LENGTH] filter = (ret > 1.0001) 1.5) 100) vol = vol[filter] ret = ret[filter] I = I[filter] J = J[filter] output = zip(I.flat,J.flat,ret.flat,vol.flat) return output results = old_function(close, volume, INTERVAL_LENGTH) results2 = new_function(close, volume, INTERVAL_LENGTH) results3 = new_function(close, volume, INTERVAL_LENGTH) # Using sets to compare, as the output # is in a different order than the original function print set(results) == set(results2) print set(results) == set(results3)
Joe Kington 18 июнь 2010, в 02:05
Поделиться
⚡ УСКОРЯЕМ PYTHON в 20 РАЗ! | Новый способ :3
Одним из ускорений будет удаление части sum , так как в этой реализации она суммирует список длиной от 2 до INTERVAL_LENGTH . Вместо этого просто добавьте volume[j+1] к предыдущему результату vol из последней итерации цикла. Таким образом, вы просто добавляете два целых числа каждый раз вместо того, чтобы суммировать весь список и нарезать его каждый раз. Кроме того, вместо того, чтобы начать с выполнения sum(volume[i+1:j+1]) , просто сделайте vol = volume[i+1] + volume[j+1] , так как вы знаете, что начальный случай здесь всегда будет всего двумя индексами.
Другим ускорением будет использование .extend вместо .append , поскольку реализация python имеет extend работает значительно быстрее.
Вы также можете разбить окончательный оператор if , чтобы при необходимости выполнять только определенные вычисления. Например, вы знаете if vol
Это не отвечает на вашу проблему точно, но я думаю, что в особенности с проблемой суммы вы должны увидеть значительные ускорения с этими изменениями.
Изменить — вам также не нужно len , поскольку вы знаете конкретно длину списка уже (если только это не было только для примера). Определение его как числа, а не len(something) всегда быстрее.
Изменить — реализация (это не проверено):
ARRAY_LENGTH = 500000 INTERVAL_LENGTH = 15 close = np.array( xrange(ARRAY_LENGTH) ) volume = np.array( xrange(ARRAY_LENGTH) ) close, volume = close.astype(‘float64’), volume.astype(‘float64’) results = [] ex = results.extend for i in xrange(ARRAY_LENGTH — INTERVAL_LENGTH): vol = volume[i+1] for j in xrange(i+1, i+INTERVAL_LENGTH): vol += volume[j+1] if vol > 100: ret = close[j] / close[i] if 1.0001 < ret < 1.5: ex( [i, j, ret, vol] ) print results
nearlymonolith 17 июнь 2010, в 23:08
Поделиться
Другим ускорением было бы определить extend_results=results.extend» once (before the loop) and then using exte_results ([i, j, ret, vol])` внутри цикла, чтобы избежать поиска. Но всегда timeit (с timeit модуля timeit при оптимизации )!
ChristopheD 17 июнь 2010, в 21:34
Интересно! Насколько значительным является время поиска? Это обычно полезное ускорение, или это больше из-за величины этого конкретного цикла?
nearlymonolith 17 июнь 2010, в 21:43
ChristopheD 17 июнь 2010, в 22:09
John Machin 17 июнь 2010, в 23:13
Спасибо! Я внес изменения — хотя 1.0001 1.0001 и ret
nearlymonolith 17 июнь 2010, в 23:22
Я почти уверен, что здесь есть проблема с вычислением vol . Срез от i + 1: j + 1 в исходном коде, и j начинается с i + 1. Для меня это означает, что vol должен быть инициализирован равным 0, а volume[j] добавлен для каждой итерации в цикле, а не для volume[j+1] .
Justin Peel 18 июнь 2010, в 14:26
Показать ещё 4 комментария
Почему бы вам не попытаться сгенерировать результат как один список (намного быстрее, чем добавлять или расширять), например:
results = [ t for t in ( (i, j, close[j]/close[i], sum(volume[i+1:j+1])) for i in xrange(len(close)-INT_LEN) for j in xrange(i+1, i+INT_LEN) ) if t[3] > 100 and 1.0001 < t[2] < 1.5 ]
Nas Banov 18 июнь 2010, в 05:20
Поделиться
Ещё вопросы
- 0 Как исчезнуть элемент при переходе?
- 1 Общие методы приводят это к T
- 0 Как добавить правило в редактор RichText с помощью плагина jquery.validate.js?
- 0 Можно ли загрузить данные изображения и отобразить в html со скрытым URL-адресом src
- 0 Как импортировать js-файл в mvc
- 0 Как издеваться над угловым сервисным методом, который принимает параметр
- 0 происхождение функции javascript [дубликаты]
- 1 Основы математики на Java
- 1 Подпись по java и openssl не совпадает
- 0 Как показать ошибки в окнах оповещений после нажатия кнопки отправки с помощью угловых JS?
- 1 Пользовательский диктант с хешируемыми ключами не может обрабатывать рекурсивные структуры
- 0 Как разделить библиотеку между процессом и вызываемым скриптом, используя SWIG?
- 1 Как проверить массив на возможные делители?
- 1 Версия Bump Gradle без столкновения с версией Android Gradle Plugin
- 0 Ошибка Zend Framework 2: оператор не может быть выполнен при реализации функции year в табличном шлюзе
- 0 Скрипт запуска Drupal jQuery для .resize ()
- 1 Как установить адаптеры вложенных представлений рециркулятора при использовании привязки данных?
- 0 В mysql Как узнать количество воскресений за месяц
- 1 Вызов процесса в C # со строковыми аргументами []
- 0 Изменить прозрачность другой вкладки при наведении курсора на текущую вкладку
- 0 Таблица отношений не обновляется, когда я вставляю записи
- 1 Xamarin Profiler вылетает приложение с самого начала
- 0 стиль шоу отличается в Chrome и Firefox Safari и iPhone
- 1 Python 3 — Сокращение списка путем циклического восстановления данного набора
- 0 Отладка в Visual Studio — могу ли я увидеть код библиотеки Intel Compiler?
- 0 Как узнать, есть ли у элемента другой элемент внутри его класса
- 1 Отсутствие практического понимания использования Play + Scala против JavaScript
- 1 Фильтр DataGridView скрывает отредактированные элементы
- 1 Robolectric Unit Test завершается неудачно с NoClassDefFoundError, когда приложение зависит от AppsFlyerLib
- 0 Добавить или удалить класс Css, когда входное значение равно нулю или не равно нулю
- 1 Способы уменьшения глубины рекурсии в Python
- 0 Как подключиться к серверу sql используя php в xampp
- 1 Как читать данные скрытой формы в функции Flask
- 1 Java jar-файл не может найти .dll с jna.jar
- 1 Как определить, что для fillStyle был назначен недопустимый цвет?
- 0 Преобразовать целые числа в символы [дубликаты]
- 1 Захват сообщения окна и затем запуск кода
- 1 Интерфейс между контроллером и сервисным уровнем
- 1 Словарь головоломки
- 1 Высокая производительность в многозадачности внутри Tomcat
- 0 Как реализовать скриптовые события для дизайна видеоигр?
- 1 Сортировать список на основе другого списка
- 1 Разбор XML и сохранение результатов в строке
- 0 Замена строкового значения в PHP
- 1 xna c # перехватить и отменить кнопку закрытия окна (x) и Ctrl F4
- 1 Найдите топ-3 в столбцах данных, используя панд
- 0 Почему я не могу использовать службу $ http в разрешении маршрута?
- 1 Какие версии Android NDK поддерживают 64-разрядные архитектуры?
- 0 Веб-браузер компилирует элементы CSS в алфавитном порядке
- 1 Как определить, попадает ли данная дата в следующую неделю / месяц
Источник: overcoder.net
Python-сообщество
- Начало
- » Python для новичков
- » code review Ребят подскажите как ускорить выполнение программы
#1 Янв. 6, 2020 20:30:12
code review Ребят подскажите как ускорить выполнение программы
Всем доброго времени суток
Написал программку, но меня не устраивает время выполнения, хотелось бы побыстрее.
Полагаю есть несколько способов как ускорить:
— Запускать в какой-то среде разработки или в консоли(я запускал в текстовом редакторе Sublime)
— Подключить какую-то библиотеку, чтоб распаралелить выполнение(в процессе выполнения, у меня, было задействовано одно ядро, процессор грузился в среднем на 17-18 %)
— Улучшить код программы
— Возможно что-то еще, о чем даже не знаю что такое может быть)
import os import pandas as pd #digit from str def extract_deg(input_str): if input_str is None or input_str == »: return 0 out_number = » f = 0 for ele in input_str: if ele.isdigit() or ele == ‘-‘: out_number += ele elif ele == ‘,’: out_number += ‘.’ f = 1 if f == 1: out_number = (float(out_number)) else: out_number = (int(out_number)) return (out_number) frame = pd.DataFrame() af = os.listdir(path=».») nf = af[10:-5] for i in nf: frame = frame.append(pd.read_csv(i), ignore_index=True) frame.to_csv(«datatest.csv», encoding=’utf-8′, sep=’t’, index=False) frame[‘minmax’] = frame[‘MAX’] — frame[‘MIN’] #массивы переменных dlst = [‘dvar1’, ‘dvar2’, . , ‘dvar11’] slst = [‘svar1’, ‘svar2’, . , ‘svar20’] elst = [‘evar1’, ‘evar2’, . , ‘evar44’] blst = [‘year’, ‘mounth’, ‘day’, ‘hh’, ‘mm’] sls = [] for i in slst: exec(i + ‘ = []’) exec(‘sls.append(‘+i+’)’) els = [] for i in elst: exec(i + ‘ = []’) exec(‘els.append(‘+i+’)’) bls = [] for i in blst: exec(i + ‘ = []’) exec(‘bls.append(‘+i+’)’) print(len(frame)) for i in range(len(frame)): year.append(int(str(frame[‘DATE’][i])[:4])) mounth.append(int(str(frame[‘DATE’][i])[4:6])) day.append(int(str(frame[‘DATE’][i])[6:8])) hh.append(int(str(frame[‘TIME’][i])[:2])) mm.append(int(str(frame[‘TIME’][i])[2:4])) time = [year[i], mounth[i], day[i], hh[i], mm[i], 0] print(i, end=’ ‘) #def1, def2 собирают текстовые данные, из которых, #при помощи extract_deg вытаскиваются числовые значения for p in range(len(dlst)-1): l = (def1(dlst[p], time)) sls[p*2].append(l[0]) sls[(p*2)+1].append(l[1]) for p in range(len(dlst)): l = (def2(dlst[p], time)) els[p*4].append(l[0]) els[(p*4)+1].append(l[1]) els[(p*4)+2].append(l[2]) els[(p*4)+3].append(l[3]) alllst = sls + els + bls salllst = slst + elst + blst for i in range(len(alllst)): frame[salllst[i]] = pd.Series(alllst[i]) frame.to_csv(«data.csv», encoding=’utf-8′, sep=’t’, index=False)
Пока вы это читаете, сделаю чтоб результат выводился не в конце выполнения программы, а к примеру каждые 10000 строк датафрейма)
Источник: python.su
Параллелизм, конкурентность и AsyncIO в Python — на примере
Конкурентность и параллелизм — похожие термины, но это не одно и то же.
Конкуренция — это возможность одновременного выполнения нескольких задач на ЦП. Задачи могут запускаться, выполняться и завершаться в перекрывающиеся периоды времени. В случае одного процессора несколько задач выполняются с помощью переключения контекстов, когда состояние процесса сохраняется, чтобы его можно было вызвать и выполнить позже.
Параллелизм — это возможность одновременного выполнения нескольких задач на нескольких ядрах процессора.
Хотя они могут увеличить скорость работы вашего приложения, параллелизм и параллельность не следует использовать повсеместно. Вариант использования зависит от того, является ли задача процессорозависимой или IO-зависимой.
Задачи, которые ограничиваются центральным процессором, привязаны к процессору. Например, математические вычисления привязаны к процессору, поскольку вычислительная мощность увеличивается с ростом числа процессоров компьютера. Параллелизм предназначен для задач, ограниченных центральным процессором. Теоретически, если задача разделена на n подзадач, каждая из этих n задач может выполняться параллельно, чтобы эффективно сократить время до 1/n исходной непараллельной задачи. Параллельность предпочтительна для задач, связанных с IO, поскольку вы можете заниматься чем-то другим, пока происходит выборка ресурсов IO.
Лучшим примером задач с привязкой к процессору является наука о данных. Специалисты по изучению данных работают с огромными массивами данных. Для предварительной обработки данных они могут разделить их на несколько пакетов и запускать их параллельно, эффективно сокращая общее время обработки. Увеличение количества ядер приводит к ускорению обработки данных.
Web scraping является IO-bound. Поскольку эта задача мало влияет на процессор, так как большая часть времени тратится на чтение из сети и запись в сеть. Другие распространенные IO-bound задачи включают вызовы баз данных, чтение и запись файлов на диск. Веб-приложения, такие как Django и Flask, являются IO-bound приложениями.
Если вам интересно узнать больше о различиях между потоками, мультипроцессингом и async в Python, ознакомьтесь со статьей Speeding Up Python with Concurrency, Parallelism, and asyncio.
Сценарий
Давайте рассмотрим, как ускорить выполнение следующих задач:
# tasks.py import os from multiprocessing import current_process from threading import current_thread import requests def make_request(num): # io-bound pid = os.getpid() thread_name = current_thread().name process_name = current_process().name print(f» — — «) requests.get(«https://httpbin.org/ip») async def make_request_async(num, client): # io-bound pid = os.getpid() thread_name = current_thread().name process_name = current_process().name print(f» — — «) await client.get(«https://httpbin.org/ip») def get_prime_numbers(num): # cpu-bound pid = os.getpid() thread_name = current_thread().name process_name = current_process().name print(f» — — «) numbers = [] prime = [True for i in range(num + 1)] p = 2 while p * p
Все примеры кода в этом руководстве можно найти в репозитории parallel-concurrent-examples-python.
- make_request делает HTTP запрос на https://httpbin.org/ip X количество раз.
- make_request_async делает тот же самый HTTP запрос асинхронно с HTTPX.
- get_prime_numbers вычисляет простые числа методом Решето Эратосфена от двух до заданного предела.
Для ускорения выполнения вышеуказанных задач мы будем использовать следующие библиотеки из стандартной библиотеки:
- поточность для одновременного выполнения задач
- multiprocessing для параллельного выполнения задач
- concurrent.futures для одновременного и параллельного выполнения задач из одного интерфейса
- asyncio для параллельного выполнения задач с корутинами, управляемыми интерпретатором Python
IO-bound Operation
Опять же, связанные с IO задачи тратят больше времени на IO, чем на CPU.
Поскольку веб-скрейпинг связан с IO, мы должны использовать потоки для ускорения обработки, поскольку получение HTML (IO) происходит медленнее, чем его разбор (CPU).
Сценарий: Как ускорить скрипт веб-скрейпинга и краулинга на базе Python?
Пример синхронизации
Начнем с эталона.
# io-bound_sync.py import time from tasks import make_request def main(): for num in range(1, 101): make_request(num) if __name__ == «__main__»: start_time = time.perf_counter() main() end_time = time.perf_counter() print(f»Elapsed run time: seconds.»)
Здесь мы сделали 100 HTTP-запросов с помощью функции make_request . Поскольку запросы происходят синхронно, каждая задача выполняется последовательно.
Elapsed run time: 15.710984757 seconds.
Итак, это примерно 0,16 секунды на один запрос.
Пример потоковой обработки
# io-bound_concurrent_1.py import threading import time from tasks import make_request def main(): tasks = [] for num in range(1, 101): tasks.append(threading.Thread(target=make_request, args=(num,))) tasks[-1].start() for task in tasks: task.join() if __name__ == «__main__»: start_time = time.perf_counter() main() end_time = time.perf_counter() print(f»Elapsed run time: seconds.»)
Здесь одна и та же функция make_request вызывается 100 раз. На этот раз для создания потока для каждого запроса используется библиотека threading .
Elapsed run time: 1.020112515 seconds.
Общее время уменьшается с ~16с до ~1с.
Поскольку мы используем отдельные потоки для каждого запроса, вы можете задаться вопросом, почему все это не заняло ~0,16 с для завершения. Это дополнительное время — накладные расходы на управление потоками. Глобальная блокировка интерпретатора (GIL) в Python гарантирует, что только один поток одновременно использует байткод Python.
concurrent.futures Пример
# io-bound_concurrent_2.py import time from concurrent.futures import ThreadPoolExecutor, wait from tasks import make_request def main(): futures = [] with ThreadPoolExecutor() as executor: for num in range(1, 101): futures.append(executor.submit(make_request, num)) wait(futures) if __name__ == «__main__»: start_time = time.perf_counter() main() end_time = time.perf_counter() print(f»Elapsed run time: seconds.»)
Здесь мы использовали concurrent.futures.ThreadPoolExecutor для достижения многопоточности. После создания всех фьючерсов/обещаний мы использовали wait , чтобы дождаться их завершения.
Elapsed run time: 1.340592231 seconds
concurrent.futures.ThreadPoolExecutor фактически является абстракцией вокруг библиотеки multithreading , что упрощает ее использование. В предыдущем примере мы назначили каждый запрос на поток, и в общей сложности было использовано 100 потоков. Но в ThreadPoolExecutor по умолчанию количество рабочих потоков равно min(32, os.cpu_count() + 4) . ThreadPoolExecutor существует для того, чтобы облегчить процесс достижения многопоточности. Если вы хотите получить больший контроль над многопоточностью, используйте вместо этого библиотеку multithreading .
Пример AsyncIO
# io-bound_concurrent_3.py import asyncio import time import httpx from tasks import make_request_async async def main(): async with httpx.AsyncClient() as client: return await asyncio.gather( *[make_request_async(num, client) for num in range(1, 101)] ) if __name__ == «__main__»: start_time = time.perf_counter() loop = asyncio.get_event_loop() loop.run_until_complete(main()) end_time = time.perf_counter() elapsed_time = end_time — start_time print(f»Elapsed run time: seconds»)
httpx используется здесь, поскольку requests не поддерживает асинхронные операции.
Здесь мы использовали asyncio для достижения параллелизма.
Elapsed run time: 0.553961068 seconds
asyncio быстрее, чем другие методы, потому что threading использует потоки ОС (операционной системы). Таким образом, потоки управляются ОС, и переключение потоков происходит с ее помощью. asyncio использует корутины, которые определяются интерпретатором Python. С помощью coroutines программа решает, когда оптимально переключать задачи. За это отвечает even_loop в asyncio.
Операция с ограничением вычислительной мощности
Сценарий: Как ускорить простой скрипт обработки данных?
Пример синхронизации
Опять же, давайте начнем с эталона.
# cpu-bound_sync.py import time from tasks import get_prime_numbers def main(): for num in range(1000, 16000): get_prime_numbers(num) if __name__ == «__main__»: start_time = time.perf_counter() main() end_time = time.perf_counter() print(f»Elapsed run time: seconds.»)
Здесь мы выполнили функцию get_prime_numbers для чисел от 1000 до 16000.
Elapsed run time: 17.863046316 seconds.
Пример многопроцессорной обработки
# cpu-bound_parallel_1.py import time from multiprocessing import Pool, cpu_count from tasks import get_prime_numbers def main(): with Pool(cpu_count() — 1) as p: p.starmap(get_prime_numbers, zip(range(1000, 16000))) p.close() p.join() if __name__ == «__main__»: start_time = time.perf_counter() main() end_time = time.perf_counter() print(f»Elapsed run time: seconds.»)
Здесь мы использовали multiprocessing для вычисления простых чисел.
Elapsed run time: 2.9848740599999997 seconds.
concurrent.futures Пример
# cpu-bound_parallel_2.py import time from concurrent.futures import ProcessPoolExecutor, wait from multiprocessing import cpu_count from tasks import get_prime_numbers def main(): futures = [] with ProcessPoolExecutor(cpu_count() — 1) as executor: for num in range(1000, 16000): futures.append(executor.submit(get_prime_numbers, num)) wait(futures) if __name__ == «__main__»: start_time = time.perf_counter() main() end_time = time.perf_counter() print(f»Elapsed run time: seconds.»)
Здесь мы добились многопроцессорности с помощью concurrent.futures.ProcessPoolExecutor . Как только задания добавляются во фьючерсы, wait(futures) ожидает их завершения.
Elapsed run time: 4.452427557 seconds.
concurrent.futures.ProcessPoolExecutor является оберткой вокруг multiprocessing.Pool . Она имеет те же ограничения, что и ThreadPoolExecutor . Если вам нужен больший контроль над многопроцессорностью, используйте multiprocessing.Pool . concurrent.futures предоставляет абстракцию как над мультипроцессингом, так и над потоками, что позволяет легко переключаться между ними.
Заключение
Стоит отметить, что использование многопроцессорной обработки для выполнения функции make_request будет намного медленнее, чем потоковый вариант, так как процессы должны будут ждать ввода-вывода. Однако многопроцессорный подход будет быстрее, чем синхронный.
Аналогично, использование параллелизма для задач, привязанных к процессору, не стоит усилий по сравнению с параллелизмом.
При этом использование параллелизма или параллельности для выполнения скриптов усложняет работу. Ваш код будет труднее читать, тестировать и отлаживать, поэтому используйте их только в случае крайней необходимости для долго выполняющихся сценариев.
concurrent.futures — это то, с чего я обычно начинаю, поскольку-
- Легко переключаться туда-сюда между параллелизмом и параллельностью
- Зависимым библиотекам не нужно поддерживать asyncio ( requests против httpx )
- Чище и легче читать по сравнению с другими подходами
Возьмите код из репозитория parallel-concurrent-examples-python на GitHub.
Источник: django.fun