Параллельные вычисления в Python

Пытаюсь написать код, который при получении новой строки через requests будет вызывать функцию get_value() отдельным процессом. Т.к. поток, получаемый через requests бывает довольно большой, и тогда обработка происходит с отставанием. Пытался реализовать разными способами, но в итоге не получается ничего вменяемого. Вот что на данный момент есть:

from checkhash import get_value
from multiprocessing import Process
import subprocess
import requests
def get_hash():
    url = 'https://somesite'
    r = requests.get(url, stream=True)
    for line in r.iter_lines():
        if line:
            hash = (str(line).split('"hash":"')[1].split('"')[0])
            print(hash)
            proc = Process(target=get_value(hash))
            procs.append(proc)
            proc.start()
if __name__ == '__main__':
    procs = []
    while True:
        get_hash()

насколько я понял, проблема в том, что срабатыват GIL, который ждёт, пока дочерний процесс завершится. Как это обойти?


Ответы (2 шт):

Автор решения: Андрей

Вот пример простого скрипта, запускающего одновременно несколько процессов:

from multiprocessing import Process
import requests

urls = ["https://google.com",
        "https://ya.ru",
        "https://mail.ru",
        "https://bing.com",
        "https://yahoo.com",
        "https://duckduckgo.com"]

def handle(url):
    page = requests.get(url)
    print(str(len(page.content)) + "\t" + url)

processes = []

for url in urls:
    p = Process(target = handle, args = (url, ))
    p.start()
    processes.append(p)

print("Processes started")

for p in processes:
    p.join()

print("Processes ended")

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

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

Адаптируйте свой скрипт и получите желаемый результат.

→ Ссылка
Автор решения: Denis Samotuga

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

import requests
import aiohttp
import asyncio

async def get_hash():
    url = 'https://somesite'
    r = requests.get(url, stream=True)
    async with aiohttp.ClientSession() as session:
        for line in r.iter_lines():
            if line:
                hash = (str(line).split('"hash":"')[1].split('"')[0])
                print(hash)
                #Далее идут преобразования, взятые из get_value(). Суть не в них, а в том, что они выполняются как и было надо, асинхронно

loop = asyncio.get_event_loop()
asyncio.run(get_hash())
→ Ссылка