LINUX.ORG.RU

Как добавить мультипоточность

 , ,


3

1

Пытаюсь осилить мультипоточность под многоядерные процы на питоне. Накатал 2 версии через Pool и через Thread, ни одна не работает.
Помогите исправить код, чтобы он эффективно работал на многоядернике.

Есть простой код бинарного сравнения двух толстых файлов. Если брать большой размер блоков (piece_size), то скорость упирается в скорость хдд. Если брать маленький размер блока, то уже сильно проседает процессор и скорость чтения с диска падает. Делаю вывод, что узким местом является операция сравнения двух частей:

from time import time

piece_size = 16 # KB
# cores in system
multiplier = 4
errors = 0
starttime = time()

# 2 equal by size, but different by content files
file1 = open('etalon.mkv', 'rb')
file2 = open('startplus.mkv', 'rb')

# get byte piece of 2 files, and compare them
def check(r1, r2, i):
    global errors
    if r1[i:i + piece_size] != r2[i:i + piece_size]:
        errors += 1
    return

if __name__ == '__main__':
    r1 = file1.read(piece_size * multiplier)
    r2 = file2.read(piece_size * multiplier)
    
    while r1:
        # give piece * 4 size, and work with every piece separately
        for i in range(0, piece_size * multiplier, piece_size):
            check(r1, r2, i)
        r1 = file1.read(piece_size * multiplier)
        r2 = file2.read(piece_size * multiplier)
    
    print('errors:', errors)
    print('Running time: ', time() - starttime)
Итог: Скорость чтения с диска 8 mb/s, 25% загрузка cpu (max for 1 core)

Попытка реализации через Pool: http://pastebin.com/u6C2tcbt
Итог: Скорость чтения с диска 0 mb/s, 4 подпроцесса в 2% cpu, 1 процесс в 25% cpu
Попытка реализации через Thread: http://pastebin.com/xkHJwkm1
Итог: Скорость чтения с диска 0 mb/s, 1 процесс в 30% cpu

★★★★★

Последнее исправление: CYB3R (всего исправлений: 2)

Ответ на: комментарий от tailgunner

ну вон я 2 попытки сделал. Но т.к. я ни разу не программист, ничего не получилось. Через мультипроцессинг тоже пробовал. Итог: Создаётся миллион процессов, каждый из которых ничего не дает и система в результате ложится...

Там похоже без семафоров не обойтись. Хотелось бы по-порще через pool и max_workers, чтоб без семафоров и внутренних броадкастов. У меня не настолько сложная задача

anonymoos ★★★★★
() автор топика
Последнее исправление: anonymoos (всего исправлений: 1)
Ответ на: комментарий от anonymoos

ну вон я 2 попытки сделал.

Ты переусложняешь. Зачем тебе apply, почему не использовать просто просто очереди? Зачем постоянно читать файлы?

Там похоже без семафоров не обойтись.

Обойтись.

tailgunner ★★★★★
()

чем вас не устраивает сравнение методом расчёта контрольных сумм через, например, md5/sha1 и без питона?

и не возникает ли у вас ощущения, что во втором чтении тоже нужно читать (piece_size * multiplier)?

mashina ★★★★★
()
Ответ на: комментарий от tailgunner

Зачем постоянно читать файлы?

Я читаю файлы небольшими кусочками. Сразу весь файл в память я записать не могу, т.к. сравниваю файлы в несколько сотен мегабайт, гигабайт

Попробовал переписать «по простому»:
for i in range(0, piece_size * multiplier, piece_size):
____multiprocessing.Process(target=check, args=(r1,r2,i,)).start()

В итоге в системе наплодилас сотня процессов, каждый из которых ничего не делал.
Добавил для проверки после этого блока sleep(1). В системе только 1 процесс стал висеть. И не делать ничего.

Не понимаю я хоть убей логику работы этого кода. Мне всего-то нужно для каждого из четырёх i, полученных в for, запустить 4 процесса. Потом повторить это столько раз, сколько нужно.

anonymoos ★★★★★
() автор топика
Ответ на: комментарий от mashina

мне не нужно просто узнать что файлы разные. Мне нужно получить ещё какой-то % различий. Точный можно получить сравнивай файлы по байту, но мне достаточно погрешности в 1%, для файлов в пару гигабайт это даёт возможност сравнивать целыми мегабайтными блоками. Считать crc для каждого кусочка не имеет смысла. Сравнение в памяти происходит практически мгновенно. Если только число этих сравнений не начинает идти на сотни тысяч

anonymoos ★★★★★
() автор топика

На python'е нет многопотоности по уолчанию. Даже если насоздаешь потоков они будут выполняться последовательно.
Для реальной многопотоности можно использовать спец. патч, pypy или на C накидать код для создания потоков.
Так что, вместо них я использовал псевдопотоки (libev)

deterok ★★★★★
()
Ответ на: комментарий от mashina

да, во втором блоке чтения описка. Но в общем на тестирование непосредственно многопоточности она не влияет

anonymoos ★★★★★
() автор топика
Ответ на: комментарий от deterok

http://docs.python.org/3/library/concurrent.futures.html не согласны с этим утверждением.
Да и остальные примерны из документации скопипасченные у меня работают как надо. Но стоит попробовать что-то применить к своему коду, как начинает сказываться непонимание принципов работы :(

На предполагаемом стенде убунта LTS, и никаких egg-сов и доп. модулей там быть не может. Только голый python 3.2

anonymoos ★★★★★
() автор топика
Последнее исправление: anonymoos (всего исправлений: 1)
Ответ на: комментарий от anonymoos

Я читаю файлы небольшими кусочками. Сразу весь файл в память я записать не могу, т.к. сравниваю файлы в несколько сотен мегабайт, гигабайт

У тебя нет двух гигабайт памяти?

Не понимаю я хоть убей логику работы этого кода.

Ты не понимаешьь того, что сам написал?

Мне всего-то нужно для каждого из четырёх i, полученных в for, запустить 4 процесса. Потом повторить это столько раз, сколько нужно.

Запусти 4 процесса и передавай им данные для обработки (альтернативно, можешь передавать им byte ranges для чтения из файла).

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

У тебя нет двух гигабайт памяти?

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

Ты не понимаешьь того, что сам написал?

Я сейчас на стадии активных попыток понимания и изучения

Запусти 4 процесса и передавай им данные для обработки

Гениально! Сейчас попробую. Не тыкните только носом в модуль, через который это делать? Уж очень много у питона для этого средств multiprocessing, threading, concurrent. У меня голова трещит от попытки понять что из этого мне стоит использовать.

anonymoos ★★★★★
() автор топика
Ответ на: комментарий от anonymoos

Сравнение в памяти происходит практически мгновенно. Если только число этих сравнений не начинает идти на сотни тысяч

через «многопоточность» так проблему не решить, т.к. читаешь блоки в главном процессе, пересылаешь их в дочерние и там сравниваешь. IPC сожрёт больше времени и CPU по сравнению с обработкой всего в одном процессе (собственно, большая часть работы приходится на основной процесс). Стоит просто сделать больше multiplier или переписывать код так, чтобы чтение тоже было в дочерних процессах.

mashina ★★★★★
()
Ответ на: комментарий от deterok

Туда opengl еще не портировали?

не в курсе. Но опенгл через PyQt работает как надо. Самая большая проблема для меня, что туда PyGtk не портировали. И в ближайшее время не собираются.

anonymoos ★★★★★
() автор топика
Ответ на: комментарий от anonymoos

не, мне нужна чистая обертка для библиотек...
Через PySide естественно все работает.

deterok ★★★★★
()
Ответ на: комментарий от anonymoos

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

Работаю программистом большую часть жизни, я могу сказать, что ты пока не пишешь программу %)

Запусти 4 процесса и передавай им данные для обработки

Не тыкните только носом в модуль, через который это делать?

Внезапно, multiprocessing. Классы Queue и Process

import multiprocessing as mp

def workfn(qin, qout):
  while True:
    inp = qin.get()
    outp = foo(inp)
    qout.put(outp)

qout = mp.Queue(4)
qin = mp.Queue(4)
for i in range(0, 4):
  p = mp.Process(target = workfn, args = (qout, qin))
  p.start()
tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

я могу сказать, что ты пока не пишешь программу %)

Я даже не претендую. Скорее изучаю инструмент эффективной автоматизации задач.

Был у меня случай, нужно было склеить в один несколько почтовых mbox хранилищ, с удалением дубликатов сообщений.
нашёл отличный скрипт, написанный в афигенном функциональном стиле, с лямбдами и рекурсиями, всё в две строчки. Файлы в 50-100 мб он ещё отрабатывал как надо. Проблема была в том, что мне нужно было склеить с пол десятка файлов размером в 50 ГБ каждый. Вот тут я ощутил все прелести софта, который просто работает со всеми данными в оперативной памяти. Матерился я долго, но пришлось писать всё самому с нуля.
С тех пор я не переварию функциональщину и полную выгрузку объектов в память ...

anonymoos ★★★★★
() автор топика
Последнее исправление: anonymoos (всего исправлений: 1)
Ответ на: комментарий от anonymoos

... суровые сибирски мужики приложили новую японскую бензопилу к железобетонному столбу. «Кряк» - сказала японская бензопила. «Ээээээ...» - сказали суровые сибирски мужики, и взяв свои топоры пошли валить лес дальше.

Вы случаем не суровый сибирский мужик? На всякий случай - в ФП (питоньем во всяк случае) есть генераторы, которые как раз таки сделаны что бы не грузить все в память.

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

AIv ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.