Реализация в многопоточном стиле
Есть код, который сейчас проходится по папкам и анализирует информацию. Он работает в однопоточном стиле. Мне нужно его в многопоточном сделать. Я так понимаю, решение будет примерно таким: thread = threading.Thread(target=функция), и в конце добавлять
for ticker in tickers:
ticker.start()
for ticker in tickers:
ticker.join()
Но я не пойму, где именно в коде это применить, что передавать в таргет. Метод open открывает файлы по ссылке и проходится построчно по ним, метод calculate рассчитывает по формуле значения из файлов.
from utilites import show_result, generate_filenames
import threading
class Ticker(threading.Thread):
def __init__(self, ticket_folder, *args, **kwargs):
super().__init__(*args, **kwargs)
self.ticket_folder = ticket_folder
self.name_ticket = ''
self.volatility = 0
def run(self):
self.calculate(self.open())
def open(self):
price_scope = []
with open(self.ticket_folder, mode='r') as open_ticker:
for element in open_ticker:
scattered_element = element.split(',')
self.name_ticket = scattered_element[0]
if scattered_element[2] != 'PRICE':
price_scope.append(float(scattered_element[2]))
return price_scope
def calculate(self, unsorted):
unsorted.sort()
half_sum = (unsorted[0] + unsorted[-1]) / 2
self.volatility = ((unsorted[-1] - unsorted[0]) / half_sum) * 100
def main(folder):
zero_tickers = []
value_key = {}
sorted_place = []
tickers = []
for last_folder in generate_filenames(folder):
tickers.append(Ticker(last_folder))
for ticker in tickers:
ticker.start()
for ticker in tickers:
ticker.join()
for ran_ticker in tickers:
if ran_ticker.volatility == 0:
zero_tickers.append(ran_ticker.name_ticket)
else:
value_key[ran_ticker.volatility] = ran_ticker.name_ticket
sorted_place.append(ran_ticker.volatility)
sorted_place.sort()
show_result(sorted_place, value_key, zero_tickers)
path = "trades/"
if __name__ == '__main__':
main(folder=path)
Как правильно этот код реализовать в многопоточном стиле?
Ответы (2 шт):
Советую создать глобальный список, например с путями к папкам. Условно назовем его mas.
Далее создать секцию для main:
if __name__ == "__main__":
Дальше можно запустить несколько потоков простым циклом:
for i in range(5):
Код, который должен исполняться следует вынести в отдельную функцию. Вы указали верный кусок кода сверху, это добавляете в цикл for.
thread = threading.Thread(target = func_name, args)
А процедуру работы программы начните с цикла while True, добавьте условие на прекращение цикла while True, если список mas оказался пустым.
Через mas.pop(0) вы можете получить первый элемент в вашем списке mas со всеми путями и папками, а также удалить этот элемент из списка mas.
Выглядеть начало вашей функции будет примерно так:
global mas
while True:
if len(mas) == 0:
break
else:
path = mas.pop(0)
...
Возможно существуют решения лучше. Не претендую на абсолютную правильность и эффективность.
def run(self) это и есть target по умолчанию. Уже применен в описании класса.
Если вынести функции run, open, calculate из класса, то функцию run передавайте как target в класс Thread, а папку там в параметр функции вместо прилипания атрибутом к экземпляру через self.
Что в вашем коде вам не нравится?
Но Ваш код создает довольно много потоков, если папок много. И так как тут расчёты то лучше все переорганизовать на multiprocessing.Pool().imap_unordered(... )