Рубрики
Без рубрики

Параллелизм в Python

Параллельность в Python Changurency – это способность разных частей или единиц программы, … Помечено Python, параллелизм, async, ждут.

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

Давайте посмотрим на пример код, который является не одновременно Отказ

import requests

urls = [
    "https://docs.python.org/3/",
    "https://github.com/trending/",
    "https://www.youtube.com/feed/trending/",
    "https://stackoverflow.com/questions/",
    "https://docs.djangoproject.com/en/3.0/",
    "https://requests.readthedocs.io/en/master/",
    "https://docs.aiohttp.org/en/stable/",
    "https://pypi.org/",
    "https://itsfoss.com/",
    "https://www.freecodecamp.org/news/",
    "https://gist.github.com/discover",
]

def get_req(url):
    res = requests.get(url)
    print(res.status_code, url)

def synchronous_function():
    for url in urls:
        get_req(url)

synchronous_function()

Приведенная выше программа отправляет запрос HTTP Get на все URL-адреса, указанные в списке URL-адресов синхронно. Что здесь значит синхронно? Это означает, что каждый запрос отправляется только после того, как предыдущий HTTP-запрос завершает I.E после того, как предыдущий запрос возвращает ответ. Таким образом, для текущего запроса, чтобы завершить его дождаться предыдущего запроса на завершение. Следовательно, код выполняется последовательно. Но что, если один URL требует много времени, чтобы ответить? Все выполнение кода приостановлено, пока мы не получим ответ. Можем ли мы сделать это лучше? Да мы можем !!.

Давайте переписываем код, чтобы каждый запрос URL независим от другого запроса URL.

import threading

def get_req(url):
    res = requests.get(url)
    print(res.status_code, url)

def threaded_function():
    threads = []
    for url in urls:
        t = threading.Thread(target=get_req, args=(url,))
        t.start()
        threads.append(t)

    for thread in threads:
        thread.join()

threaded_function()

Приведенный выше код использует модуль резьбы Python и использует потоки. Нитки являются небольшим набором отдельных программ, которые выполняются независимо, несколько потоков могут работать при перекрывающихся временных интервалах. В отличие от других языков программирования нити в Python различны. Они не бегают параллельно, только один поток работает в определенное время из-за GIL.

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

  • Для каждого URL-адреса мы создаем новую тему и сделайте новый запрос HTTP Get.
  • Нить запускает работать I.e, выполняется Python.

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

Давайте копаем глубже на то, что здесь перекрывают время означает

  • Предположим, что есть 2 URL-адреса и 2 потока
  • Мы знаем, что Python может выполнить только один поток за раз
  • Тема 1 Отправляет HTTP-запрос и ждет ответа на URL 1.
  • в то время как Тема 1 ждет ответ Тема 2 Отправляет еще один HTTP-запрос и ждет ответа, поэтому, когда Тема 2 ждет, мы бы уже получили ответ на Тема 1 URL и позже мы получаем ответ на Тема 2 ур

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

Но здесь есть еще одна проблема, обычно многоподобные программы трудно реализовать и дизайн.

Python 3.5 представил Async/ждут. Асинхронное программирование улучшает производительность для блокировки операций, работая одновременно. Таким образом, когда эти функции были введены, не было много библиотек, чтобы использовать его мощность. Библиотеки, как AioHTTP , httpx ETC поддерживает Async/ждут.

Давайте переписать вышеуказанную программу, чтобы использовать Async/a ждать

import asyncio

import httpx

async def async_get(url):
    client = httpx.AsyncClient()
    res = await client.get(url)
    print(res.status_code, url)
    await client.aclose()


async def async_func():
    async_funcs = [async_get(url) for url in urls]
    await asyncio.gather(*async_funcs)

asyncio.run(async_func())

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

Здесь вы можете найти полный код с тестами

import asyncio
import threading
import time

import httpx
import requests


urls = [
    "https://docs.python.org/3/",
    "https://github.com/trending/",
    "https://www.youtube.com/feed/trending/",
    "https://stackoverflow.com/questions/",
    "https://docs.djangoproject.com/en/3.0/",
    "https://requests.readthedocs.io/en/master/",
    "https://docs.aiohttp.org/en/stable/",
    "https://pypi.org/",
    "https://itsfoss.com/",
    "https://www.freecodecamp.org/news/",
    "https://gist.github.com/discover",
]


def get_req(url):
    res = requests.get(url)
    # print(res.status_code, url)


def synchronous_function():
    for url in urls:
        get_req(url)


def threaded_function():
    threads = []
    for url in urls:
        t = threading.Thread(target=get_req, args=(url,))
        t.start()
        threads.append(t)

    for thread in threads:
        thread.join()


def time_taken_for(func):
    start_time = time.perf_counter()
    func()  # or func.__call__()
    end_time = time.perf_counter()
    total_time = end_time - start_time
    print(
        "total time taken for function {} : {:.3f} seconds".format(
            func.__name__, total_time
        ),
    )


async def async_get(url):
    client = httpx.AsyncClient()
    res = await client.get(url)
    # print(res.status_code, url)
    await client.aclose()


async def async_func():
    async_funcs = [async_get(url) for url in urls]
    await asyncio.gather(*async_funcs)


def time_taken_for_async_req():
    start_time = time.perf_counter()
    asyncio.run(async_func())
    end_time = time.perf_counter()
    total_time = end_time - start_time
    print("total time taken for async function : {:.3f} seconds".format(total_time),)


if __name__ == "__main__":
    time_taken_for(synchronous_function)
    time_taken_for(threaded_function)
    time_taken_for_async_req()



# total time taken for function synchronous_function : 10.250 seconds

# total time taken for function threaded_function : 1.369 seconds

# total time taken for async function : 1.315 seconds

Оригинал: “https://dev.to/sreevardhanreddi/concurrency-in-python-565o”