简体   繁体   English

并行循环Python中的循环

[英]Parallel while Loops in Python

I'm pretty new to Python, and programming in general and I'm creating a virtual pet style game for my little sister. 我是Python的新手,一般的编程,我正在为我的妹妹创建一个虚拟宠物风格的游戏。

Is it possible to run 2 while loops parallel to each other in python? 在python中是否可以运行2 while循环? eg: 例如:

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)

If not, is there some way that I can turn this into one loop? 如果没有,是否有某种方法可以将其转换为一个循环? I want the stuff in the second loop to happen every 20 seconds, but the stuff in the first loop to by constantly happening. 我希望第二个循环中的东西每20秒发生一次,但第一个循环中的东西会不断发生。

Thanks for any help 谢谢你的帮助

Have a look at Threading.Timer . 看看Threading.Timer

There is a code recipe here to schedule a function to run every 5 seconds . 这里有一个代码配方来安排一个每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)

The only way to "have two while loops in parallel" would be to place them on different threads, but then you need to tackle the synchronization and coordination problems between them since they're reaching into the same object. “并行两个while循环”的唯一方法是将它们放在不同的线程上,但是你需要解决它们之间的同步和协调问题,因为它们到达同一个对象。

I suggest you instead put a time check in the first (and single) loop and perform the increases that you now have in the second loop proportionately to that time-check; 我建议你改为在第一个(和单个)循环中进行时间检查,然后按照与时间检查成比例的方式执行第二个循环中的增量; not quite satisfactory since the buttonbox call might take an indefinite amount of time to return, but way simpler to arrange, esp. 不是中规中矩,因为buttonbox调用可能需要很长时间才能返回不确定的量,但更简单的方式来安排,ESP。 for a beginner, than proper threading coordination. 对于初学者而言,不是适当的线程协调。

Once you do have the basic logic in place and working, then you can consider threads again (with a periodic timer for what you'd like in the 2nd loop in one thread, the blocking buttonbox call in the main thread [[I think in easygui it has to be]], both feeding events into a Queue.Queue [[intrinsically thread-safe]] with another thread getting them and operating accordingly, ie most of what you now have in the 1st loop). 一旦你有了基本的逻辑和工作, 那么你可以再次考虑线程(在一个线程的第二个循环中使用周期性计时器,在主线程中阻塞按钮框调用[[我想在easygui必须是]],将事件送入Queue.Queue [[本质上是线程安全]],另一个线程获取它们并相应地操作,即你现在在第一个循环中拥有的大部分内容)。 But that's quite an advanced architectural problem, which is why I recommend you don't try to deal w/it right now!-) 但这是一个相当高级的架构问题,这就是为什么我建议你现在不要尝试处理它! - )

You should use State Machines for this (see the Apress pygame book - downloads here: http://apress.com/book/downloadfile/3765 ), see chapter 7. 您应该使用状态机(请参阅Apress pygame书 - 在此处下载: http//apress.com/book/downloadfile/376​​5 ),请参阅第7章。

A simplified state machine: 简化的状态机:

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')

put one of them into a function, the threading.Thread class supports a target attribute: 将其中一个放入一个函数中,threading.Thread类支持一个target属性:

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

Will start yourFunc() running in the background. 将启动yourFunc()在后台运行。

Essentially to have processing to happen in parallel you have several solutions 基本上要使处理并行发生,您可以使用多种解决方案

1- Separate processes (ie: programs) running independently that speak to one another through a specific protocol (eg: Sockets) 1-独立运行的独立进程(即:程序),通过特定协议(例如:套接字)相互通信

2- Or you can have the one process spawn off multiple threads 2-或者你可以让一个进程产生多个线程

3- Build an event queue internally and process them one by one 3-在内部构建事件队列并逐个处理它们

That is the general picture. 这是一般情况。

As for the specific answer to your question, you said "the stuff in the first loop to b[e] constantly happening". 至于你问题的具体答案,你说“第一个循环中的东西b [e]不断发生”。 The reality is you never want this to happen all the time, because all that will do is use up 100% of the CPU and nothing else will ever get done 实际情况是你永远不希望这种情况一直发生,因为所有这一切都会占用100%的CPU,而其他任何东西都无法完成

The simplest solution is probably number 3. 最简单的解决方案可能是3号。

The way I would implement it is in my main loop have a thread that goes through an event queue and sets a timer for each event. 我实现它的方式是在我的主循环中有一个线程,它通过一个事件队列并为每个事件设置一个计时器。 Once all the timers have been sent the main loop then goes to sleep. 一旦所有定时器都被发送到主循环然后进入休眠状态。

When a timer times out, an other function will then run the corresponding function for the event that triggered that timer. 当计时器超时时,另一个函数将为触发该计时器的事件运行相应的函数。

In your case, you have two events. 在您的情况下,您有两个事件。 One for displaying the selection menu (first loop) and the second for changing myPotatoHead. 一个用于显示选择菜单(第一个循环),另一个用于更改myPotatoHead。 The timer associated with the first one, I would set to 0.5sec, making it larger reduces CPU usage but slows down responsivness, increasing it usses up more CPU, for the second event I would set a 20 second timer. 与第一个相关联的计时器,我将设置为0.5秒,使其更大,降低CPU使用率,但减慢响应速度,增加它使用更多的CPU,对于第二个事件,我将设置20秒计时器。

Ofcourse when the timer expires, you would not do while 1 but you will just go through your while loop body once (ie get rid of while). 当计时器到期时,你不会做while 1但是你只需要通过你的while循环体一次(即摆脱它)。

i think they cannot be coupled in to one while loop. 我认为他们不能耦合到一个while循环。 maybe you need to check the threading or multiprocessing library. 也许你需要检查线程或多处理库。

There is also a package called SimPy that you could also look at. 还有一个名为SimPy的软件包,您也可以查看。 The threading and multiprocessing libraries may also help. 线程多处理库也可能有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM