Параллельно пока Loops в Python - PullRequest
3 голосов
/ 20 января 2010

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

Возможно ли запустить 2 , в то время как петли параллельны друг другу в питоне? например:

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 ]

3 голосов
/ 20 января 2010

Для этого вы должны использовать State Machines (см. Книгу по пигмею Apress - здесь: 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')
3 голосов
/ 20 января 2010

Единственный способ «иметь два параллельных цикла while» - это разместить их в разных потоках, но тогда вам необходимо решить проблемы синхронизации и координации между ними, поскольку они достигают одного и того же объекта.

Я предлагаю вам вместо этого поставить проверку времени в первом (и единственном) цикле и выполнить увеличение, которое вы сейчас имеете во втором цикле, пропорционально этой проверке времени; не вполне удовлетворительно, поскольку вызов buttonbox может занять неограниченное количество времени для возврата, но способ проще организовать, особенно для начинающего, чем правильная координация потоков.

Как только у вас есть базовая логика, которая работает и работает, затем вы можете снова рассмотреть потоки (с периодическим таймером для того, что вы хотите во 2-м цикле в одном потоке, вызов блокирующей кнопки в главном потоке [[я думаю, что в easygui это должно быть]], оба события передаются в Queue.Queue [[по сути поточно-ориентированный]], а другой поток получает их и работает соответственно, т.е. 1-й цикл). Но это довольно сложная архитектурная проблема, поэтому я рекомендую вам не пытаться решать ее прямо сейчас! -)

2 голосов
/ 20 января 2010

поместите один из них в функцию threading.Thread поддерживает целевой атрибут:

import threading
threading.Thread(target=yourFunc).start()

Запустит yourFunc () в фоновом режиме.

1 голос
/ 20 января 2010

По существу, чтобы параллельная обработка выполнялась, у вас есть несколько решений

1- Отдельные процессы (т.е. программы), работающие независимо, которые общаются друг с другом через определенный протокол (например, сокеты)

2- Или вы можете запустить один процесс из нескольких потоков

3 - Построить внутреннюю очередь событий и обработать их одну за другой

Это общая картина.

Что касается конкретного ответа на ваш вопрос, вы сказали, что «материал в первом цикле будет постоянно происходить». Реальность такова, что вы никогда не хотите, чтобы это происходило постоянно, потому что все, что вам нужно, это использовать 100% ЦП, и больше ничего не будет сделано

Самое простое решение, вероятно, номер 3.

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

Когда таймер истекает, другая функция затем запускает соответствующую функцию для события, которое вызвало этот таймер.

В вашем случае у вас есть два события. Один для отображения меню выбора (первый цикл), а второй для изменения myPotatoHead. Таймер, связанный с первым, я бы установил на 0,5 с, увеличивая его, сокращая использование ЦП, но замедляя скорость отклика, увеличивая его использование, увеличивая использование ЦП, для второго события я бы установил 20-секундный таймер.

Конечно, когда время таймера истечет, вы не сделаете while 1, а просто пройдете тело цикла while один раз (т.е. избавитесь от while).

0 голосов
/ 20 января 2010

Существует также пакет под названием SimPy , который вы также можете посмотреть.Также могут помочь многопроцессорные библиотеки и .

0 голосов
/ 20 января 2010

я думаю, что они не могут быть связаны с одним циклом while. возможно, вам нужно проверить многопоточность или многопроцессорную библиотеку .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...