Наличие нескольких потоков, выполняющих действия на основе глобальной переменной

Я пытаюсь заставить один поток изменить глобальную переменную, а затем другие потоки проверить эту глобальную переменную и, если она изменится, выполнить какое-то действие. Я прочитал многопоточность документации по python, но все это для меня очень ново, и я не уверен, какие варианты лучше всего подходят для того, что я пытаюсь сделать, или то, что я делаю, глупо, и есть лучший способ? Этот код не изменяет операторы цветной печати, как я и ожидал. (Кроме того, этот код должен быть в python 2.x для некоторых других модулей, которые я использую в своем реальном проекте.) ... возможно, мне следует использовать объект очереди.

import random
import sys
import threading
import time

# Globals
output = None

class Green(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        while True:
            if output == 'green':
                print 'green'
                time.sleep(1)


class Red(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        while True:
            if output == 'red':
                print 'red'
                time.sleep(1)


class Color_Randomizer(threading.Thread):
    def __init__(self):
        global output
        threading.Thread.__init__(self)

    def run(self):
        while True:
            colors = ['red', 'green']
            output = random.choice(colors)
            time.sleep(1)


def main():

    green = Green()
    red = Red()
    color_randomizer = Color_Randomizer()

    print 'Starting green'
    green.start()
    print 'Starting red'
    red.start()
    print 'Starting color randomizer'
    color_randomizer.start()

if __name__ == "__main__":
    main()

person Michael    schedule 05.05.2015    source источник
comment
return output - зачем ты это делаешь?   -  person user2357112 supports Monica    schedule 05.05.2015
comment
Этого не должно быть, спасибо.   -  person Michael    schedule 05.05.2015


Ответы (2)


Вы никогда не изменяете глобальную переменную output.. Переменная output в ColorRandomizer.run — это локальная переменная, которая затеняет глобальную.

Вставьте строку global output в верхнюю часть функции run Color_Randomizer.

Удалите оператор return output в Color_Randomizer(). Ваш time.sleep вызов в следующей строке недоступен. Кроме того, нет смысла возвращать значение из потока, потому что нет возможности его использовать.

person Paul Cornelius    schedule 05.05.2015
comment
Это заработало, спасибо. А я посмотрю очереди на основе комментариев @mpolednik. - person Michael; 05.05.2015
comment
Я поддержу все замечания @mpolednik. И добавьте, что вы также должны изучить потоки демонов и понять проблемы, связанные с упорядоченным завершением многопоточных программ. В вашем примере красные и зеленые потоки должны быть демонами. - person Paul Cornelius; 06.05.2015
comment
Спасибо, Павел, очень ценю вашу помощь. Сейчас читаю демонов. - person Michael; 06.05.2015

Код в данном случае очень простой, поэтому многие скрытые проблемы здесь не видны. На самом деле видно первое: использование глобальных переменных в целом не самый лучший способ.

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

Имеет смысл общаться с потоками — использование очереди — одна из возможностей. Вы бы отправили текущий цвет и ответили темы, которые понимают, как обращаться с этим цветом. Это соответствует тому, как вы справляетесь с коммуникацией в параллельной (или параллельной в случае Python) среде.

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

person mpolednik    schedule 05.05.2015