Параллельные циклы while в Python
Я довольно новичок в Python и программировании в целом, и я создаю игру в стиле виртуального питомца для моей младшей сестры.
Можно ли запустить 2 , пока циклы параллельны друг другу в python?
например:
while 1:
input_event_1 = gui.buttonbox(
msg = 'Hello, what would you like to do with your Potato Head?',
title = 'Main Screen',
choices = ('Check Stats', 'Feed', 'Exercise', 'Teach', 'Play', 'Go to Doctor', 'Sleep', 'Change Favourite Thing', 'Get New Toy', 'Quit'))
if input_event_1 == 'Check Stats':
myPotatoHead.check_p_h_stats()
elif input_event_1 == 'Feed':
myPotatoHead.feed_potato_head()
elif input_event_1 == 'Exercise':
myPotatoHead.exercise_potato_head()
elif input_event_1 == 'Teach':
myPotatoHead.teach_potato_head(myPotatoHead)
elif input_event_1 == 'Play':
myPotatoHead.play_with_toy()
elif input_event_1 == 'Sleep':
myPotatoHead.put_p_h_asleep()
elif input_event_1 == 'Go to Doctor':
myPotatoHead.doctor_check_up()
elif input_event_1 == 'Change Favourite Thing':
myPotatoHead.change_favourite_thing()
elif input_event_1 == 'Quit':
input_quit = gui.ynbox(
msg = 'Are you sure you want to quit?',
title = 'Confirm quit',
choices = ('Quit', 'Cancel'))
if input_quit == 1:
sys.exit(0)
while 1:
time.sleep(20)
myPotatoHead.hunger = str(float(myPotatoHead.hunger) + 1.0)
myPotatoHead.happiness = str(float(myPotatoHead.happiness) - 1.0)
myPotatoHead.tiredness = str(float(myPotatoHead.tiredness) + 1.0)
Если нет, то есть ли какой-то способ превратить это в один цикл?
Я хочу, чтобы вещи во втором цикле происходили каждые 20 секунд, но вещи в первом цикле постоянно происходили.
Спасибо за любую помощь
7 ответов:
Взгляните на нарезание резьбы.Таймер .
Здесь есть рецепт кода , чтобы запланировать выполнение функции каждые 5 секунд.
import thread import threading class Operation(threading._Timer): def __init__(self, *args, **kwargs): threading._Timer.__init__(self, *args, **kwargs) self.setDaemon(True) def run(self): while True: self.finished.clear() self.finished.wait(self.interval) if not self.finished.isSet(): self.function(*self.args, **self.kwargs) else: return self.finished.set() class Manager(object): ops = [] def add_operation(self, operation, interval, args=[], kwargs={}): op = Operation(interval, operation, args, kwargs) self.ops.append(op) thread.start_new_thread(op.run, ()) def stop(self): for op in self.ops: op.cancel() self._event.set() if __name__ == '__main__': # Print "Hello World!" every 5 seconds import time def hello(): print "Hello World!" timer = Manager() timer.add_operation(hello, 5) while True: time.sleep(.1)
Единственный способ" иметь два цикла while параллельно " - это разместить их в разных потоках, но тогда вам нужно решить проблемы синхронизации и координации между ними, поскольку они достигают одного и того же объекта.
Я предлагаю вам вместо этого поставить проверку времени в первом (и единственном) цикле и выполнить увеличение, которое вы теперь имеете во втором цикле пропорционально этой проверке времени; не совсем удовлетворительно, так как вызов
buttonboxможет занять неопределенное количество времени вернуться, но Путь проще устроить, esp. для новичка, чем правильная координация резьбы.Как только у вас есть основная логика на месте и работает, затем вы можете рассмотреть потоки снова (с периодическим таймером для того, что вы хотели бы во 2-м цикле в одном потоке, блокирующий вызов buttonbox в главном потоке [[я думаю, что в easygui это должно быть]], оба подавая события в очередь.Очередь [[внутренне потокобезопасно]] с другим потоком, получающим их и работающим соответственно, то есть большую часть того, что вы сейчас имеете в 1-м цикле). Но это довольно сложная архитектурная проблема, поэтому я рекомендую вам не пытаться решать ее прямо сейчас!- )
Для этого вы должны использовать государственные машины (см. Apress pygame book-downloads здесь: http://apress.com/book/downloadfile/3765 ), см. Главу 7.
Упрощенная государственная машина:
def do_play(pet, time_passed): pet.happiness += time_pass*4.0 def do_feed(pet, time_passed): pet.hunger -= time_passed*4.0 def do_sleep(pet, time_passed): pet.tiredness += time_passed*4.0 if pet.tiredness <= 0: return 'Waiting' def do_waiting(pet, time_passed): pass def do_howl(pet, time_passed): print 'Hoooowl' def do_beg(pet, time_passed): print "I'm bored!" def do_dead(pet, time_passed): print '...' STATE_TO_FUNC = dict(Waiting=do_waiting, Sleeping=do_sleep, Feeding=do_feed, Playing=do_play, Howling=do_howl, Begging=do_beg, Dead=do_dead ) class Pet: def __init__(self): self.state = 'Waiting' self.hunger = 1.0 self.tiredness = 1.0 self.happiness = 1.0 def process(self, time_passed): self.hunger +=1*time_passed self.tiredness +=1*time_passed self.happiness -= 1*time_passed func = STATE_TO_FUNC[self.state] new_state = func(self, time_passed) if new_state is not None: self.set_state(new_state) if self.hunger >10: self.set_state('Dead') elif self.hunger > 5 and not (self.state == 'Feeding'): self.set_state('Howling') elif self.tiredness > 5: self.set_state('Sleeping') elif self.happiness < 0 and not (self.state == 'Playing'): self.set_state('Begging') def set_state(self,state): if not self.state == 'Dead': self.state = state from msvcrt import getch import time pet = Pet() while True: time0 = time.time() cmd = getch() # what command? pet.process(time.time()-time0) if cmd == 'a': pet.set_state('Feeding') if cmd == 's': pet.set_state('Sleeping') if cmd == 'd': pet.set_state('Playing')
Поместите один из них в функцию, поток.Класс Thread поддерживает целевой атрибут:
import threading threading.Thread(target=yourFunc).start()Запустит yourFunc (), работающий в фоновом режиме.
По существу, чтобы обработка происходила параллельно, у вас есть несколько решений
1-отдельные процессы (т. е.: программы), работающие независимо, которые говорят друг с другом через определенный протокол (например: сокеты)
2-или вы можете заставить один процесс порождать несколько потоков
3 - Создайте внутреннюю очередь событий и обработайте их один за другим
Такова общая картина.Что касается конкретного ответа на ваш вопрос, Вы сказали: "материал в первая петля к б [е] постоянно происходит". Реальность такова, что вы никогда не хотите, чтобы это происходило все время, потому что все, что будет сделано, это использовать 100% процессора, и ничего больше никогда не будет сделано
Самым простым решением, вероятно, является число 3.
Я бы реализовал это так: в моем основном цикле есть поток, который проходит через очередь событий и устанавливает таймер для каждого события. После того, как все таймеры были отправлены основной цикл затем переходит в спящий режим.
Когда таймер истекает, другой затем функция запустит соответствующую функцию для события, которое запустило этот таймер.
В вашем случае, у вас есть два события. Один для отображения меню выбора (первый цикл), а второй для изменения myPotatoHead. Таймер, связанный с первым, я бы установил на 0,5 сек, что делает его больше, уменьшает нагрузку на процессор, но замедляет скорость реагирования, увеличивая его использование больше процессора, для второго события я бы установил 20-секундный таймер.
Конечно, когда таймер истекает, вы бы не делайте
while 1, но вы просто пройдете через свое тело циклаwhileодин раз (т. е. избавитесь от while).
Я думаю, что они не могут быть связаны в один цикл while. возможно, вам нужно проверить библиотекуthreading илиmultiprocessing .
Существует также пакет под названиемSimPy , который вы также можете посмотреть. Также могут помочь библиотекиthreading иmultiprocessing .
Comments