С Новым годом! Форум программистов, компьютерный форум, киберфорум
Python для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/3: Рейтинг темы: голосов - 3, средняя оценка - 4.67
10 / 6 / 5
Регистрация: 04.04.2017
Сообщений: 14
1

Устранение узкого места в многопроцессной программе

07.12.2019, 19:39. Показов 570. Ответов 2
Метки нет (Все метки)

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

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
''' Counting specified key sequence in the specified file
and printing result to the standard output with elapsed time '''
 
import sys
import argparse
from multiprocessing import Manager, Process
 
from timeit import default_timer as timer
 
def worker(lines_slices, keyseq, results):
    counter = 0
 
    # подсчет количества совподений в каждой строке
    for line in lines_slices:
        counter += line.count(keyseq)
 
    # сохранение результата подсчета в очереде
    results.put(counter)
 
def main(argv_slice):
    res = 0
 
    # разбор аргументов командной строки
    parser = argparse.ArgumentParser(
        description='Counting key sequence in the file')
 
    parser.add_argument('-f', '--fpath', type=str, required=True,
                        help='File path to reading')
    parser.add_argument('-k', '--keyseq', type=str, required=True,
                        help='Key sequence to counting')
 
    parsed_argv = parser.parse_args(argv_slice)
 
    fpath = parsed_argv.fpath
    keyseq = parsed_argv.keyseq
 
    with open(fpath) as fin:
        start = timer()
 
        manager = Manager()
 
        # считывание всего содержимого исходного файла
        lines = fin.readlines()
 
        # создание очереди для хранения результатов
        results = manager.Queue()
 
        processes_list = [] # список процессов
 
        lines_slices = [] # список ссылок на данные
 
        processes_count = 1
 
        process_part = len(lines) / processes_count
 
        # цикл инициализации и создания потоков выполнения
        for process_index in range(0, processes_count):
            from_index = process_index * int(process_part)
 
            if process_index != processes_count - 1:
                to_index = from_index + int(process_part)
            else:
                to_index = len(lines)
 
            # создание дополнительной ссылки на данные для каждого потока !!!
            lines_slices.append(lines[from_index:to_index])
 
            # сохранение дескриптора потока в списке потоков
            processes_list.append(Process(target=worker,
                                          args=(lines_slices[process_index],
                                                keyseq, results)))
 
            processes_list[process_index].start()
 
        # ожидание завершения потоков выполнения
        for process_index in range(0, processes_count):
            processes_list[process_index].join()
 
        custom_counter = 0
 
        # расчет окончательного результата подсчета
        for process_index in range(0, processes_count):
            custom_counter += results.get()
 
        elapsed = timer() - start # расчет затраченного времени на вычисление
 
    print('Counter: {}'.format(custom_counter))
    print('Elapsed: {}'.format(elapsed))
    
    return res
 
if __name__ == '__main__':
    sys.exit(main(sys.argv[1:]))
Тест программы с одним процессом:
Код
C:\Users\DPC\Desktop>python ./keyseqfinder.py -f ".\Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 11.7325519

C:\Users\DPC\Desktop>python ./keyseqfinder.py -f ".\Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 10.1927612

C:\Users\DPC\Desktop>python ./keyseqfinder.py -f ".\Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 9.8788877

C:\Users\DPC\Desktop>python ./keyseqfinder.py -f ".\Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 9.7096962

C:\Users\DPC\Desktop>python ./keyseqfinder.py -f ".\Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 9.2697762

C:\Users\DPC\Desktop>
Тест программы с двумя процессами:
Код
C:\Users\DPC\Desktop>python ./keyseqfinder.py -f "Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 8.733194699999999

C:\Users\DPC\Desktop>python ./keyseqfinder.py -f "Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 8.6498893

C:\Users\DPC\Desktop>python ./keyseqfinder.py -f "Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 8.703362700000001

C:\Users\DPC\Desktop>python ./keyseqfinder.py -f "Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 8.5597862

C:\Users\DPC\Desktop>python ./keyseqfinder.py -f "Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 8.717497

C:\Users\DPC\Desktop>
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
07.12.2019, 19:39
Ответы с готовыми решениями:

Устранение узкого места в многопоточной программе
Доброго времени суток, столкнулся с узким местом при разработке много поточной программы на питоне....

Поиск "узкого" места и варианты решения
Есть сервер (i3 WS2003 4 Gb RAID5 1Tb 1x1Gbit/s Lan), на нём в общей папке, весом в 18 Гб, лежат...

Устранение ошибок в программе
написала программу. выдает очень много ошибок. #include "stdafx.h" #include "stdio.h" #define...

Устранение ошибок в программе с NAudio
Здравствуйте. Есть такая задача: Нужно реализовать программу. В программе есть текстовое поле и...

2
Просто Лис
Эксперт Python
5966 / 3729 / 1097
Регистрация: 17.05.2012
Сообщений: 10,787
Записей в блоге: 9
07.12.2019, 20:30 2
Воркеры чуточку не так пишутся. Вы создали очередь, но не используете её. Главный поток должен класть задания в очередь, а воркеры забирать (и крутиться в вечном цикле, ожидая задания из очереди).

Если написать воркеры так, то можно нарезать входной файл на одинаковые кусочки (10-20-сколько угодно) и выдавать задания воркерам.

У вас, скорей всего, много данных, поэтому прирост производительности от параллелизма будет "съедаться" на пересылку данных процессам.

Добавлено через 1 минуту
Уточнение: очередей должно быть две: входная и выходная.
1
10 / 6 / 5
Регистрация: 04.04.2017
Сообщений: 14
08.12.2019, 23:19  [ТС] 3
Сделал примерно так, как сказал Рыжий Лис, но вместо объекта Process используется объект Pool:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
''' Counting specified key sequence in the specified file
and printing result to the standard output with elapsed time '''
 
import sys
import argparse
from multiprocessing import Manager, Pool
 
from timeit import default_timer as timer
 
keyseq = str()
results = None
 
def worker_init(first, second):
    global keyseq
    global results
 
    keyseq = first
    results = second
 
def worker(lines_slices):
    global keyseq
    global results
    
    counter = 0
 
    # подсчет количества совподений в каждой строке
    for line in lines_slices:
        counter += line.count(keyseq)
 
    # сохранение результата подсчета в очереде
    results.put(counter)
 
def main(argv_slice):
    res = 0
 
    # разбор аргументов командной строки
    parser = argparse.ArgumentParser(
        description='Counting key sequence in the file')
 
    parser.add_argument('-f', '--fpath', type=str, required=True,
                        help='File path to reading')
    parser.add_argument('-k', '--keyseq', type=str, required=True,
                        help='Key sequence to counting')
 
    parsed_argv = parser.parse_args(argv_slice)
 
    fpath = parsed_argv.fpath
    keyseq = parsed_argv.keyseq
 
    with open(fpath) as fin:
        start = timer()
 
        manager = Manager()
 
        # считывание всего содержимого исходного файла
        lines = fin.readlines()
 
        # создание очереди для хранения результатов
        results = manager.Queue()
 
        pool_size = 1
 
        pool = Pool(processes=pool_size, initializer=worker_init,
                    initargs=[keyseq, results])
 
        pool_size *= 1 # теперь pool_size определяет количество порций данных
 
        lines_slices = [] # список ссылок на данные
 
        pool_part = len(lines) / pool_size
 
        # цикл разбиения даннных на равные порции
        for pool_index in range(0, pool_size):
            from_index = pool_index * int(pool_part)
 
            if pool_index != pool_size - 1:
                to_index = from_index + int(pool_part)
            else:
                to_index = len(lines)
 
            lines_slices.append(lines[from_index:to_index])
 
        pool.map(worker, lines_slices)
 
        pool.close()
 
        pool.join();
 
        custom_counter = 0
 
        # расчет окончательного результата подсчета
        while not results.empty():
            custom_counter += results.get()
 
        elapsed = timer() - start # расчет затраченного времени на вычисление
 
    print('Counter: {}'.format(custom_counter))
    print('Elapsed: {}'.format(elapsed))
    
    return res
 
if __name__ == '__main__':
    sys.exit(main(sys.argv[1:]))
Тест программы с одним процессом и не разделенными данными:
Код
C:\Users\DPC\Desktop>python ./keyseqfinder.py -f "Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 9.741935000000002

C:\Users\DPC\Desktop>python ./keyseqfinder.py -f "Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 9.9012215

C:\Users\DPC\Desktop>python ./keyseqfinder.py -f "Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 9.848994

C:\Users\DPC\Desktop>python ./keyseqfinder.py -f "Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 9.721278000000002

C:\Users\DPC\Desktop>python ./keyseqfinder.py -f "Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 9.761334900000001

C:\Users\DPC\Desktop>
Тест программы с пятью процессами и пятидесятью порциями данных:
Код
C:\Users\DPC\Desktop>python ./keyseqfinder.py -f "Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 6.8526908

C:\Users\DPC\Desktop>python ./keyseqfinder.py -f "Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 6.853741800000001

C:\Users\DPC\Desktop>python ./keyseqfinder.py -f "Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 6.8378956

C:\Users\DPC\Desktop>python ./keyseqfinder.py -f "Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 6.7401488

C:\Users\DPC\Desktop>python ./keyseqfinder.py -f "Всякие записи.txt" -k "Абишев Данияр"
Counter: 396144
Elapsed: 7.0934037

C:\Users\DPC\Desktop>
Непонятно было как определить оптимальное количество процессов в пуле - поэтому пришлось экспериментировать. Выяснил, что быстрее всего программа работает при пяти процессах в пуле и с пятидесятью порциями данных.

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

Скорее всего я где-то ошибся при использовании процессов и пуллов процессов - потому-что результат увеличения производительности совсем не велик...
0
08.12.2019, 23:19
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
08.12.2019, 23:19
Помогаю со студенческими работами здесь

fstream в многопроцессной среде
Не нашел в гугле ответа на следующие вопросы: 1. Что происходит когда ifstream открывает, затем...

Узкие места в программе
Есть старая большая программа, которую хочется оптимизировать, она в принципе написана...

Как закрыть фрейм из другого места в программе?
Я умею создавать фремы с кнопками, по нажатии на крестик или кнопку с действием dispose() окно...

Выбор места для хранения текста в программе
Добрый вечер. Мне в программе надо выводить на экран небольшой текст на родном языке (50 строк по...

Инжект более узкого скоупа в широкий
Всем привет. Имеем синглтон: @Singleton @LocalBean @Lock(LockType.READ) public class...

Подключение дополнительного рабочего места для работы в программе через файл-сервер
Сразу извините, если не в правильную тему задал вопрос. Нужна помощь и подсказка как правильно...

Устройство для создания узкого воздушного потока
Здравствуйте, хотелось бы узнать есть ли какой-либо мини компрессор для создания воздушного потока...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Новые блоги и статьи
Книги и учебные ресурсы по C#
InfoMaster 08.01.2025
Базовые учебники и руководства Одной из лучших книг для начинающих является "C# 10 и . NET 6 для начинающих" Эндрю Троелсена и Филиппа Джепикса . Книга последовательно раскрывает основные концепции. . .
Что такое NullReferenceEx­­­ception и как исправить?
InfoMaster 08.01.2025
NullReferenceException - одно из самых распространенных исключений, с которым сталкиваются разработчики на C#. Это исключение возникает при попытке обратиться к членам объекта (методам, свойствам или. . .
Что такое Null Pointer Exception (NPE) и как это исправить?
InfoMaster 08.01.2025
Null Pointer Exception (NPE) - это одно из самых распространенных исключений в Java, которое возникает при попытке использовать ссылку на объект, значение которой равно null. Это исключение относится. . .
Русский язык в консоли C++
InfoMaster 08.01.2025
При разработке программ на C++ одной из частых проблем, с которой сталкиваются русскоязычные программисты, является корректное отображение кириллицы в консольных приложениях. Эта проблема особенно. . .
Telegram бот на C#
InfoMaster 08.01.2025
Разработка ботов для Telegram стала неотъемлемой частью современной экосистемы мессенджеров. C# предоставляет мощный и удобный инструментарий для создания разнообразных ботов, от простых. . .
Использование GraphQL в Go (Golang)
InfoMaster 08.01.2025
Go (Golang) является одним из наиболее популярных языков программирования, используемых для создания высокопроизводительных серверных приложений. Его архитектурные особенности и встроенные. . .
Что лучше использовать при создании класса в Java: сеттеры или конструктор?
Alexander-7 08.01.2025
Вопрос подробнее: На вопрос: «Когда одновременно создаются конструктор и сеттеры в классе – это нормально?» куратор уточнил: «Ваш класс может вообще не иметь сеттеров, а только конструктор и геттеры. . .
Как работать с GraphQL на TypeScript
InfoMaster 08.01.2025
Введение в GraphQL и TypeScript В современной разработке веб-приложений GraphQL стал мощным инструментом для создания гибких и эффективных API. В сочетании с TypeScript, эта технология. . .
Счётчик на базе сумматоров + регистров и генератора сигналов согласования.
Hrethgir 07.01.2025
Создан с целью проверки скорости асинхронной логики: ранее описанного сумматора и предополагаемых fast регистров. Регистры созданы на базе ранее описанного, предполагаемого fast триггера. То-есть. . .
Как перейти с Options API на Composition API в Vue.js
BasicMan 06.01.2025
Почему переход на Composition API актуален В мире современной веб-разработки фреймворк Vue. js продолжает эволюционировать, предлагая разработчикам все более совершенные инструменты для создания. . .
Архитектура современных процессоров
inter-admin 06.01.2025
Процессор (центральный процессор, ЦП) является основным вычислительным устройством компьютера, которое выполняет обработку данных и управляет работой всех остальных компонентов системы. Архитектура. . .
История создания реляционной модели баз данных, правила Кодда
Programming 06.01.2025
Предпосылки создания реляционной модели В конце 1960-х годов компьютерная индустрия столкнулась с серьезными проблемами в области управления данными. Существовавшие на тот момент модели данных -. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru