@EarlAthos

Как передавать данные между потоками на Python?

Искал в интернете решения, с использованием Value, Arrays. Не сильно разобрался, по этому прошу помощи.
Идея такая. Подбрасываем монетку много раз и смотрим, сколько раз выпал орёл и сколько раз - решка. Сначала проблема была в том, что если бросать монетку 10млн раз, и для статистики повторить это 10 раз, то программа выполнялась долго. Почитал информацию про потоки, написал код, где монетка подбрасывается 10-ю потоками в каждом по 10млн раз. Было быстрее раза в 3.5. Но, предположим, мне надо подбросить монетку не 10млн раз, а 100млн раз. В один поток это выполняется долго(около 25 минут). В 4 потока по-идее около 7 минут. Но в 4 потока я получаю данные монетки, подброшенной по 25млн. раз и так 4 раза. Как можно передавать информацию между потоками, пробовал через текстовый файл. Но работает не всегда корректно. Иногда не отрабатывает в полном объёме. Т.е. кол-во бросков меняется (25млн/50млн/75млн/100млн), я догадываюсь, почему так происходит, но из-за того, что плохо разбираюсь в теме программирования, не уверен.
Начал учиться Python недавно, для общего развития, так что, вероятно, что код ужасен. Прошу поправлять, дабы я мог получить больше знаний на эту тему.

Сам код:
import random
import os
import time
from multiprocessing import Process

def rnd(kolvo):
    start_time = time.time() # Сохраняем время
    o = 0 # Количество "орлов"
    r = 0 # Количество "решек"
    kol = 0 # Всего бросков
    proc = os.getpid() # Получаем номер процесса, для отладки
    while kol != kolvo:
        # Кидаем монетку
        tmp = random.randint(0, 1)
        if tmp == 0:
            o = int(o) + 1
        if tmp == 1:
            r = int(r) + 1
        kol = kol + 1
    # Читаем из файла информацию о бросках и монетках
    file = open('test.txt', 'r', encoding='utf-8')
    read = file.readlines()
    file.close()
    # Перезаписываем файл с учетом полученной информации
    file = open('test.txt', 'w', encoding='utf-8')
    file.write(str(int(read[0]) + kol) + '\n' + str(int(read[1]) + o) + '\n' + str(int(read[2]) + r))
    file.close()
    # Для отладки
    print('Номер процесса - ' + str(proc))
    print("--- %s секунд ---" % (time.time() - start_time))

if __name__ == '__main__': # Не понял зачем эта строка, но так работает
    start_time = time.time() # Сохраняем время
    # Создаём файл со значениями 0\n0\n0 что бы при считывании получить list
    file = open('test.txt', 'w', encoding='utf-8')
    file.write('0\n0\n0\n')
    file.close()
    kolvo = 2500000 # Количество бросков для каждого процесса

    # Инициализируем
    proc1 = Process(target=rnd, args=(kolvo,))
    proc2 = Process(target=rnd, args=(kolvo,))
    proc3 = Process(target=rnd, args=(kolvo,))
    proc4 = Process(target=rnd, args=(kolvo,))

    # Стартууууууем
    proc1.start()
    proc2.start()
    proc3.start()
    proc4.start()
    # Для отладки
    #print("--- %s секунд --- Процессы стартанули!" % (time.time() - start_time))

    # Заканчиваем
    proc1.join()
    proc2.join()
    proc3.join()
    proc4.join()

    # Считываем данные из файла и выводим их на экран
    file = open('test.txt', 'r', encoding='utf-8')
    read = file.readlines()
    file.close()
    print('% выпадения решки ' + str(int(read[2])*100/int(read[0])))
    print('% выпадения орла ' + str(int(read[1])*100/int(read[0])))
    print('Всего бросков ' + str(int(read[0])))

    print("--- %s секунд --- ВЕСЬ КОД!" % (time.time() - start_time)) # Время выполнения всего кода
  • Вопрос задан
  • 5904 просмотра
Решения вопроса 1
@bbkmzzzz
if __name__ == '__main__': # Не понял зачем эта строка, но так работает

При запуске файла на исполнение интерпретатор создает переменные окружения, для того файла, который запустили переменная __name__ == '__main__'. Если файл импортировали, в __name__ будет относительный путь к модулю, и в блок кода после if управление не попадет. (при импорте файл исполняется)

multiprocessing.Queue. Это синхронизированная очередь.
Создайте экземпляр и отдайте его каждому потоку. Поток пусть добавляет каждую итерацию расчета в список, а список потом отдает в очередь. Как только все потоки завершены, пробегаете по очереди, обрабатываете списки, делаете с ними что хотите.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
tumbler
@tumbler Куратор тега Python
бекенд-разработчик на python
* Во-первых, нормально работать в несколько потоков Вам помешает GIL
* Во-вторых, синхронизировать все результаты не обязательно, вам в конце ведь только счетчики нужны
* Смотрите модуль multiprocessing, он позволяет выполнять методы в отдельных процессах
* В каждом процессе считаете свою статистику, потом получаете результаты в главном процессе и суммируете.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы