🐍 ΠšΠΎΠ½ΠΊΡƒΡ€Π΅Π½Ρ‚Π½ΠΎΡΡ‚ΡŒ ΠΈ ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΠΈΠ·ΠΌ Π² Python: Π² Ρ‡Π΅ΠΌ Ρ€Π°Π·Π½ΠΈΡ†Π°?

Π’ ΡΡ‚Π°Ρ‚ΡŒΠ΅ Π½Π° простых ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°Ρ… Ρ€Π°ΡΡΠΌΠ°Ρ‚Ρ€ΠΈΠ²Π°ΡŽΡ‚ΡΡ ΠΊΠΎΠ½Ρ†Π΅ΠΏΡ†ΠΈΠΈ конкурСнтности ΠΈ ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΠΈΠ·ΠΌΠ° Π² Python ΠΈ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Ρ‹ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с этими концСпциями: ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΡ‚ΠΎΡ‡Π½ΠΎΡΡ‚ΡŒ, сoroutines, asyncio ΠΈ ΠΌΠ½ΠΎΠ³ΠΎΠΏΡ€ΠΎΡ†Π΅ΡΡΠΎΡ€Π½ΠΎΡΡ‚ΡŒ.
🐍 ΠšΠΎΠ½ΠΊΡƒΡ€Π΅Π½Ρ‚Π½ΠΎΡΡ‚ΡŒ ΠΈ ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΠΈΠ·ΠΌ Π² Python: Π² Ρ‡Π΅ΠΌ Ρ€Π°Π·Π½ΠΈΡ†Π°?

ΠŸΡ€ΠΈ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ слоТных систСм с большим количСством Π·Π°Π΄Π°Ρ‡, синхронноС Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ этих Π·Π°Π΄Π°Ρ‡ Π² ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎΠΌ ΠΈΡ‚ΠΎΠ³Π΅ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Ρ‚ ΠΊ падСнию ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ.

ΠšΠΎΠ½ΠΊΡƒΡ€Π΅Π½Ρ‚Π½ΠΎΡΡ‚ΡŒ ΠΈ ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΠΈΠ·ΠΌ – это ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΡ‹ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π½Ρ‹Π΅ для исправлСния этой ситуации ΠΏΡƒΡ‚Π΅ΠΌ «пСрСплСтСния» Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… Π·Π°Π΄Π°Ρ‡, Π»ΠΈΠ±ΠΎ ΠΏΡƒΡ‚Π΅ΠΌ ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ выполнСния.

Π­Ρ‚ΠΈ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΡ‹ ΠΌΠΎΠ³ΡƒΡ‚ ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒΡΡ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹ΠΌΠΈ, Π½ΠΎ Ρƒ Π½ΠΈΡ… ΡΠΎΠ²Π΅Ρ€ΡˆΠ΅Π½Π½ΠΎ Ρ€Π°Π·Π½Ρ‹Π΅ Ρ†Π΅Π»ΠΈ.

ΠšΠΎΠ½ΠΊΡƒΡ€Π΅Π½Ρ‚Π½ΠΎΡΡ‚ΡŒ

ЦСль конкурСнтности – ΠΏΡ€Π΅Π΄ΠΎΡ‚Π²Ρ€Π°Ρ‚ΠΈΡ‚ΡŒ Π²Π·Π°ΠΈΠΌΠΎΠ±Π»ΠΎΠΊΠΈΡ€ΠΎΠ²ΠΊΠΈ Π·Π°Π΄Π°Ρ‡ ΠΏΡƒΡ‚Π΅ΠΌ ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ ΠΌΠ΅ΠΆΠ΄Ρƒ Π½ΠΈΠΌΠΈ, ΠΊΠΎΠ³Π΄Π° ΠΎΠ΄Π½Π° ΠΈΠ· Π·Π°Π΄Π°Ρ‡ Π²Ρ‹Π½ΡƒΠΆΠ΄Π΅Π½Π° ΠΆΠ΄Π°Ρ‚ΡŒ внСшнСго рСсурса. Π’ΠΈΠΏΠΈΡ‡Π½Ρ‹ΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ – ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… сСтСвых запросов.

Π’Π°Ρ€ΠΈΠ°Π½Ρ‚ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ конкурСнтности – запуск запросов ΠΏΠΎ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ, ΠΏΠΎΠΊΠ° запросы Π½Π΅ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ΡΡ. Π—Π΄Π΅ΡΡŒ, ΠΎΠ΄Π½Π°ΠΊΠΎ, Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° со ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒΡŽ ΠΈ ΡΡ„Ρ„Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒΡŽ.

РСшСниС ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ – Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ запросы ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ, Π° Π·Π°Ρ‚Π΅ΠΌ ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒΡΡ ΠΌΠ΅ΠΆΠ΄Ρƒ Π½ΠΈΠΌΠΈ ΠΏΠΎ ΠΌΠ΅Ρ€Π΅ получСния ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ².

ΠŸΠ°Ρ€Π°Π»Π»Π΅Π»ΠΈΠ·ΠΌ

ΠŸΡ€ΠΈΠΌΠ΅Ρ€: Π•ΡΡ‚ΡŒ 10 Ρ€Π°Π±ΠΎΡ‡ΠΈΡ…. НС Ρ…ΠΎΡ‚Π΅Π»ΠΎΡΡŒ Π±Ρ‹, Ρ‡Ρ‚ΠΎΠ±Ρ‹ 1 Ρ€Π°Π±ΠΎΡ‡ΠΈΠΉ Ρ€Π°Π±ΠΎΡ‚Π°Π», Π° ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ 9 сидСли ΠΈ Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ Π΄Π΅Π»Π°Π»ΠΈ.

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ²Ρ‹ΡΠΈΡ‚ΡŒ ΡΡ„Ρ„Π΅ΠΊΡ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ, трСбуСтся Ρ€Π°Π·Π΄Π΅Π»ΠΈΡ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Ρƒ ΠΌΠ΅ΠΆΠ΄Ρƒ Π½ΠΈΠΌΠΈ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Ρ€Π°Π±ΠΎΡ‚Π° Π²Ρ‹ΠΏΠΎΠ»Π½ΡΠ»Π°ΡΡŒ быстрСС.

ΠŸΠ°Ρ€Π°Π»Π»Π΅Π»ΠΈΠ·ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Ρ‚Ρƒ ΠΆΠ΅ ΠΊΠΎΠ½Ρ†Π΅ΠΏΡ†ΠΈΡŽ, которая примСняСтся ΠΊ Π°ΠΏΠΏΠ°Ρ€Π°Ρ‚Π½Ρ‹ΠΌ рСсурсам. Π Π΅Ρ‡ΡŒ ΠΈΠ΄Π΅Ρ‚ ΠΎ максимальном использовании этих рСсурсов ΠΏΡƒΡ‚Π΅ΠΌ запуска процСссов ΠΈΠ»ΠΈ ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ², ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΡ… всС ядра процСссора, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌΠΈ располагаСт ΠΊΠΎΠΌΠΏΡŒΡŽΡ‚Π΅Ρ€.

ОбС эти ΠΊΠΎΠ½Ρ†Π΅ΠΏΡ†ΠΈΠΈ ΠΏΠΎΠ»Π΅Π·Π½Ρ‹ для ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… Π·Π°Π΄Π°Ρ‡, Π½ΠΎ трСбуСтся Π²Ρ‹Π±Ρ€Π°Ρ‚ΡŒ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ для ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΉ Π·Π°Π΄Π°Ρ‡ΠΈ.

ΠšΠΎΠ½ΠΊΡƒΡ€Π΅Π½Ρ‚Π½ΠΎΡΡ‚ΡŒ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΈΡ‚ для Π·Π°Π΄Π°Ρ‡, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ сильно зависят ΠΎΡ‚ Π²Π½Π΅ΡˆΠ½ΠΈΡ… рСсурсов, Π° ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΠΈΠ·ΠΌ – для Π·Π°Π΄Π°Ρ‡ интСнсивно ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΡ… ЦП.

Как Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с этими концСпциями Π² Python?

Python прСдоставляСт ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΡ‹ для Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ конкурСнтности ΠΈ ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΠΈΠ·ΠΌΠ° : для конкурСнтности ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΡ‚ΠΎΡ‡Π½ΠΎΡΡ‚ΡŒ ΠΈ Π°ΡΠΈΠ½Ρ…Ρ€ΠΎΠ½Π½ΠΎΡΡ‚ΡŒ, для ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΠΈΠ·ΠΌΠ° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΌΠ½ΠΎΠ³ΠΎΠΏΡ€ΠΎΡ†Π΅ΡΡΠΎΡ€Π½ΠΎΡΡ‚ΡŒ.

ΠœΠ½ΠΎΠ³ΠΎΠΏΠΎΡ‚ΠΎΡ‡Π½ΠΎΡΡ‚ΡŒ

ΠŸΠΎΡ‚ΠΎΠΊ ΠΏΠΎΡ…ΠΎΠΆ Π½Π° ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΡƒΡŽ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡƒ: Ρƒ Π½Π΅Π³ΠΎ Π΅ΡΡ‚ΡŒ Π½Π°Ρ‡Π°Π»ΠΎ, процСсс Ρ€Π°Π±ΠΎΡ‚Ρ‹ ΠΈ ΠΎΠΊΠΎΠ½Ρ‡Π°Π½ΠΈΠ΅ Ρ€Π°Π±ΠΎΡ‚Ρ‹. Π’ ΠΌΠΎΠΌΠ΅Π½Ρ‚ выполнСния ΠΏΠΎΡ‚ΠΎΠΊΠ° сущСствуСт СдинствСнная Ρ‚ΠΎΡ‡ΠΊΠ° выполнСния, ΠΎΠ΄Π½Π°ΠΊΠΎ ΠΏΠΎΡ‚ΠΎΠΊ Π½Π΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° β€” ΠΏΠΎΡ‚ΠΎΠΊ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ выполнятся сам ΠΏΠΎ сСбС.

ΠŸΠΎΡ‚ΠΎΠΊ выполнСния β€” ΠΎΠ΄Π½Π° ΠΈΠ»ΠΈ нСсколько Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ, нСзависимо ΠΎΡ‚ ΠΎΡΡ‚Π°Π»ΡŒΠ½ΠΎΠΉ части ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹.

Рассмотрим Π΄Π²Π° способа ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² Π² Python:

  • Π‘ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ².
  • Π‘ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ThreadPoolExecutor, созданного Π² качСствС ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Π° контСкста. Π­Ρ‚ΠΎ простой способ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΈ ΡƒΠ½ΠΈΡ‡Ρ‚ΠΎΠΆΠ°Ρ‚ΡŒ ΠΏΡƒΠ».
        import logging
import threading
import time
from concurrent.futures import ThreadPoolExecutor


def main():
    logging.info(f"************** Multiple threads with threading ****************")
    threads = list()
    for _ in range(3):
        logging.info(f"Main function: create and start thread {_+1}.")
        x = threading.Thread(target=thread_function, args=(_,))
        threads.append(x)
        x.start()

    for _, thread in enumerate(threads):
        logging.info(f"Main function: before joining thread {_+1}.")
        thread.join()
        logging.info(f"Main function: thread {_+1} done")

    logging.info(f"************** Multiple threads with ThreadPoolExecutor ****************")

    with ThreadPoolExecutor(max_workers=3) as executor:
        executor.map(thread_function, range(3))


def thread_function(name):
    logging.info(f"Thread starting: {name+1}")
    time.sleep(5)
    logging.info(f"Thread {name+1}: 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"{__file__} executed in {elapsed:0.2f} seconds.")

    

Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ Π²Ρ‹ΡˆΠ΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ создаСтся функция, которая запускаСтся Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΏΠΎΡ‚ΠΎΠΊΠ°Ρ…. Π­Ρ‚Π° функция запускаСт ΠΏΠΎΡ‚ΠΎΠΊ, Π° Π·Π°Ρ‚Π΅ΠΌ засыпаСт, имитируя Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ внСшнСС врСмя оТидания.

Π’ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ 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 {data_stream['url']}: {data_stream['data_stream'][:200]}")
        logging.info(f"-------------------------------------------------------------------------------------")

    logging.info(f"******************************************************")


def thread_function(url, collected_data):
    connection = url_request.urlopen(url)
    data_stream = connection.read()
    collected_data.append({'url': url, 'data_stream': data_stream})


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"{__file__} executed in {elapsed:0.2f} seconds.")

    

Π’ этом кускС ΠΊΠΎΠ΄Π° использована ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΡ‚ΠΎΡ‡Π½ΠΎΡΡ‚ΡŒ для ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠ³ΠΎ чтСния Π΄Π°Π½Π½Ρ‹Ρ… ΠΈΠ· Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… URL-адрСсов, выполнСния Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… экзСмпляров thread_function() ΠΈ сохранСния Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ² Π² спискС.

Как Π²ΠΈΠ΄Π½ΠΎ ΠΈΠ· ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°, ThreadPoolExecutor ΡƒΠΏΡ€ΠΎΡ‰Π°Π΅Ρ‚ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Ρ… ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ². Π₯отя это простой ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ большС URL-адрСсов, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ ThreadPoolExecutor Π½Π΅ доТидаясь ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΎΡ‚Π²Π΅Ρ‚Π°.

Из ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½Ρ‹Ρ… Π²Ρ‹ΡˆΠ΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠ² Π²ΠΈΠ΄Π½ΠΎ, Ρ‡Ρ‚ΠΎ ΠΏΠΎΡ‚ΠΎΠΊΠΈ β€” это ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΉ ΠΈ понятный способ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Π·Π°Π΄Π°Ρ‡, ΠΎΠΆΠΈΠ΄Π°ΡŽΡ‰ΠΈΡ… Π΄Ρ€ΡƒΠ³ΠΈΡ… рСсурсов. Π’Π°ΠΊΠΆΠ΅ Π²ΠΈΠ΄Π½ΠΎ, Ρ‡Ρ‚ΠΎ стандартная Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Python поставляСтся с высокоуровнСвыми рСализациями, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π΅Ρ‰Π΅ большС ΡƒΠΏΡ€ΠΎΡ‰Π°ΡŽΡ‚ эту Π·Π°Π΄Π°Ρ‡Ρƒ.

Π‘ΠΎΠ»ΡŒΡˆΠ΅ ΠΏΠΎΠ»Π΅Π·Π½Ρ‹Ρ… ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»ΠΎΠ² Π²Ρ‹ Π½Π°ΠΉΠ΄Π΅Ρ‚Π΅ Π½Π° нашСм Ρ‚Π΅Π»Π΅Π³Ρ€Π°ΠΌ-ΠΊΠ°Π½Π°Π»Π΅ Β«Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° питониста»

Coroutines ΠΈ asyncio

Coroutines (сопрограммы) – Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΉ способ ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠ³ΠΎ выполнСния Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ посрСдством ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹Ρ… конструкций, Π° Π½Π΅ систСмных ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ².

Π‘ΠΎΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ° – общая структура управлСния, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΏΠΎΡ‚ΠΎΠΊΠΎΠΌ совмСстно пСрСдаСтся ΠΌΠ΅ΠΆΠ΄Ρƒ двумя ΠΏΠΎΠ΄ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠ°ΠΌΠΈ Π±Π΅Π· Π²ΠΎΠ·Π²Ρ€Π°Ρ‚Π°. ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ ΠΎΠ΄Π½ΠΎΠΏΠΎΡ‚ΠΎΡ‡Π½ΡƒΡŽ ΠΎΠ΄Π½ΠΎΠΏΡ€ΠΎΡ†Π΅ΡΡΠΎΡ€Π½ΡƒΡŽ ΠΊΠΎΠ½ΡΡ‚Ρ€ΡƒΠΊΡ†ΠΈΡŽ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΡƒΡŽ ΠΊΠΎΠΎΠΏΠ΅Ρ€Π°Ρ‚ΠΈΠ²Π½ΡƒΡŽ ΠΌΠ½ΠΎΠ³ΠΎΠ·Π°Π΄Π°Ρ‡Π½ΠΎΡΡ‚ΡŒ.

Π’ Ρ‚ΠΎ врСмя, ΠΊΠ°ΠΊ ΠΌΠ½ΠΎΠ³ΠΎΠΏΠΎΡ‚ΠΎΡ‡Π½ΠΎΡΡ‚ΡŒ Π±Π΅Ρ€Π΅Ρ‚ ΠΈ запускаСт Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΏΠΎΡ‚ΠΎΠΊΠ°Ρ…, asyncio Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΏΠΎΡ‚ΠΎΠΊΠ΅ ΠΈ Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ Ρ†ΠΈΠΊΠ»Ρƒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ событий ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ с нСсколькими Π·Π°Π΄Π°Ρ‡Π°ΠΌΠΈ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ каТдая ΠΈΠ· Π½ΠΈΡ… Π²Ρ‹ΠΏΠΎΠ»Π½ΡΠ»Π°ΡΡŒ ΠΏΠΎ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ Π² ΠΎΠΏΡ‚ΠΈΠΌΠ°Π»ΡŒΠ½ΠΎΠ΅ врСмя.

Π Π΅Π°Π»ΠΈΠ·ΡƒΠ΅ΠΌ это Π½Π° Python с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ asyncio, ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‰Π΅ΠΉ основу ΠΈ API для запуска ΠΈ управлСния сопрограммами с ΠΊΠ»ΡŽΡ‡Π΅Π²Ρ‹ΠΌΠΈ словами async ΠΈ await.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€:

        import asyncio
import logging
import time


async def async_function(number):
    logging.info(f"Starting Async function: {number}")
    await asyncio.sleep(1)
    logging.info(f"Finishing Async function: {number}")


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"{__file__} executed in {elapsed:0.2f} 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 {'url': url, 'data_stream': data_stream}


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 {data_stream['url']}: {data_stream['data_stream'][:200]}")
        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"{__file__} executed in {elapsed:0.2f} seconds.")

    

Π’ ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ Ρ€Π°Π±ΠΎΡ‚Ρ‹ с ΠΏΠΎΡ‚ΠΎΠΊΠ°ΠΌΠΈ, Π³Π΄Π΅ любая функция выполняСтся Π² ΠΏΠΎΡ‚ΠΎΠΊΠ΅, Π² сопрограммС Ρ‡Π΅Ρ‚ΠΊΠΎ указываСтся Π² синтаксисС, ΠΊΠ°ΠΊΠΈΠ΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‚ΡΡ ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½ΠΎ.

Π’Π°ΠΊΠΆΠ΅ сопрограммы Π½Π΅ связаны Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π½Ρ‹ΠΌΠΈ ограничСниями ΠΊΠ°ΠΊ ΠΏΠΎΡ‚ΠΎΠΊΠΈ ΠΈ Ρ‚Ρ€Π΅Π±ΡƒΡŽΡ‚ мСньшС памяти ΠΈΠ·-Π·Π° Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‚ΡΡ Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΏΠΎΡ‚ΠΎΠΊΠ΅.

Однако, Ρ‚Ρ€Π΅Π±ΡƒΡŽΡ‚ΡΡ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΊΠΎΠ΄ Π±Ρ‹Π» написан с использованиСм собствСнного синтаксиса, ΠΏΠ»ΠΎΡ…ΠΎ ΡΠΎΡ‡Π΅Ρ‚Π°ΡŽΡ‰Π΅Π³ΠΎΡΡ с синхронным ΠΊΠΎΠ΄ΠΎΠΌ.

ΠœΠ½ΠΎΠ³ΠΎΠΏΡ€ΠΎΡ†Π΅ΡΡΠΎΡ€Π½ΠΎΡΡ‚ΡŒ

ΠœΠ½ΠΎΠ³ΠΎΠΏΡ€ΠΎΡ†Π΅ΡΡΠΎΡ€Π½ΠΎΡΡ‚ΡŒ – ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ, Ρ€Π°Π·Ρ€Π΅ΡˆΠ°ΡŽΡ‰ΠΈΠΉ ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡ‚ΡŒ рСсурсоСмкиС Π·Π°Π΄Π°Ρ‡ΠΈ, запуская нСзависимыС экзСмпляры ΠΈΠ½Ρ‚Π΅Ρ€ΠΏΡ€Π΅Ρ‚Π°Ρ‚ΠΎΡ€Π° 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: {name+1}")
    time.sleep(5)
    logging.info(f"Process finishing: {name+1}")


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"{__file__} executed in {elapsed:0.2f} 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 {data_stream['url']}: {data_stream['data_stream'][:200]}")
        logging.info(f"-------------------------------------------------------------------------------------")

    logging.info(f"********************************************************")


def request_function(url):
    connection = url_request.urlopen(url)
    data_stream = str(connection.read())
    return {'url': url, 'data_stream': data_stream}


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"{__file__} executed in {elapsed:0.2f} seconds.")

    

Π’ Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π΅ Π²Ρ‹ΡˆΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Pool() прСдставляСт ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡƒΡŽ Π³Ρ€ΡƒΠΏΠΏΡƒ процСссов, которая сопоставляСт ΠΈΡ‚Π΅Ρ€Π°Ρ†ΠΈΠΈ для распрСдСлСния ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΌ экзСмпляром Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ.

ΠŸΡ€Π΅ΠΈΠΌΡƒΡ‰Π΅ΡΡ‚Π²ΠΎ: каТдая опСрация выполняСтся Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠΉ срСдС выполнСния Python ΠΈ Π½Π° ΠΏΠΎΠ»Π½ΠΎΠΌ ядрС ЦП, Ρ‡Ρ‚ΠΎ Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ процСссы интСнсивно ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‰ΠΈΠ΅ ЦП.

НСдостаток: ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ подпроцСсс Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ копию Π΄Π°Π½Π½Ρ‹Ρ… (с ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ подпроцСсс Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚), ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½Π½Ρ‹Ρ… ΠΈΠ· Π³Π»Π°Π²Π½ΠΎΠ³ΠΎ процСсса ΠΈ, ΠΊΠ°ΠΊ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ, Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΡŽΡ‰ΠΈΡ… Π΄Π°Π½Π½Ρ‹Π΅ Π² Π³Π»Π°Π²Π½Ρ‹ΠΉ процСсс.

***

Π’ ΡΡ‚Π°Ρ‚ΡŒΠ΅ Π±Ρ‹Π»ΠΈ рассмотрСны ΠΊΠΎΠ½Ρ†Π΅ΠΏΡ†ΠΈΠΈ:

  • ΠšΠΎΠ½ΠΊΡƒΡ€Π΅Π½Ρ‚Π½ΠΎΡΡ‚ΡŒ.
  • ΠŸΠ°Ρ€Π°Π»Π»Π΅Π»ΠΈΠ·ΠΌ.

И ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Ρ‹ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с этими концСпциями:

  • ΠœΠ½ΠΎΠ³ΠΎΠΏΠΎΡ‚ΠΎΡ‡Π½ΠΎΡΡ‚ΡŒ.
  • Coroutines ΠΈ asyncio.
  • ΠœΠ½ΠΎΠ³ΠΎΠΏΡ€ΠΎΡ†Π΅ΡΡΠΎΡ€Π½ΠΎΡΡ‚ΡŒ.

ΠœΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Ρ‹ ΠΏΠΎ Ρ‚Π΅ΠΌΠ΅

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊΠΈ

ΠœΠ•Π ΠžΠŸΠ Π˜Π―Π’Π˜Π―

ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΈ

Π›Π£Π§Π¨Π˜Π• БВАВЬИ ПО Π’Π•ΠœΠ•