线程完成后通知主线程

时间:2012-06-18 09:08:34

标签: python multithreading

我对Python编程很新,而Threads不是我的专业领域。我有一个问题,我希望这里的人可以帮助我。

任务:作为我的硕士论文的一部分,我需要制作一个涉及多人游戏功能的混合现实游戏。在我的游戏设计中,每个玩家可以设置一堆陷阱,每个陷阱在特定时间段内都是活动的,例如30秒为了在所有玩家之间保持一致的游戏状态,所有时间检查都需要在服务器端完成,这是用Python实现的。

我决定启动一个python线程,每次玩家放置一个新陷阱并在线程上运行一个计时器。所有这一部分都很好,但真正的问题出现在我需要通知主线程这个特定陷阱的时间到了,以便我可以将它传达给客户端(android设备)。

我尝试创建一个队列并在任务完成时将信息插入队列,但我不能做一个queue.join(),因为它会将主线程置于保持状态,直到任务完成,这不是我的意思在我的情况下,需要也不是理想的,因为主线程经常与客户沟通,如果它被停止,那么与玩家的所有通信都将陷入停顿。

我需要正在运行计时器的辅助线程告诉主线程,一旦时间用完,时间已经用完并发送陷阱的ID,这样我就可以将这些信息传递给Android客户端删除它。我怎样才能实现这个目标?

关于如何在不启动大量线程的情况下实现此任务的任何其他建议也欢迎.. :):)

提前感谢您的帮助..

干杯

3 个答案:

答案 0 :(得分:2)

我终于找到了一个用python编写的一个很好的小任务调度程序,它实际上非常轻便,并且通过回调机制为后来的时间或日期安排事件非常方便,这允许子线程将值传递给主线程通知主线程的状态以及作业是否成功完成。

那里的人,需要与问题类似的功能而且不想与线程讨价还价可以使用此调度程序来安排他们的事件并在事件完成时获得回调

这是指向APScheduler

的链接

答案 1 :(得分:1)

在主线程中完成定时器可能更容易 - 有一个定时器列表,你可以继续添加新的定时器。每个计时器实际上并没有任何东西,它只是有一段时间熄灭 - 如果你在任意'轮次'工作比实时工作更容易,但仍然可行。每个间隔,主循环应该检查它们的全部,并查看它们是否到期的时间(或过去的时间) - 如果是,将它们从列表中删除(当然,要小心从列表中删除项目'重复迭代 - 它可能没有你所期望的)。

如果您有一个批次的计时器,并且通过分析发现每个间隔运行所有这些都会花费您太多时间,一个简单的优化就是将它们保存在{ {3}} - 这将保持它们为你排序,所以你知道在第一个尚未过期之后,其余的都没有。类似的东西:

while True:
    if not q:
       break
    timer = heapq.heappop(q)
    if timer.expiry <= currenttime:
       # trigger events
    else:
       heapq.heappush(q)
       break

这仍然会花费你一个不必要的弹出/推送对,但很难看出你会怎样做得更好 - 再次,做类似的事情:

for timer in q:
    if timer.expiry <= currenttime:
       heapq.heappop(timer)
       # trigger events
    else:
       break

因为列表迭代器(heapq中的函数处理序列并使用副作用,而不是由于某种原因存在一个完整的heapq类),因此可以产生微妙的错误索引它们是 - 所以如果你删除当前元素,你将一个索引向左推后,最后跳过下一个索引。

唯一重要的是currenttime在主循环中的每个间隔都会不断更新(或者,如果您的心脏根据系统时钟实时设置它),{{1} }以相同的单位进行测量 - 如果你有'回合'的概念,并且陷阱持续六轮,当它被放置时你会timer.expiry

如果您确实希望以多线程方式执行此操作,那么使用生产者/消费者队列进行清理的方式将起作用 - 您只需要不使用heapq.heappush(q, Timer(expiry=currenttime+6)。相反,当线程中的计时器用完时,它会调用Queue.join(),然后死掉。主循环将使用q.put(),这将避免阻塞,或者q.get(False)将阻止最多0.1秒 - 超时可以是任何正数;仔细调整它,以便在阻塞足够长的客户端通知和事件发生迟到之间进行最佳权衡,因为他们只是错过了按时排队。

答案 2 :(得分:0)

主线程创建一个队列和一堆工作线程 从队列中拉出任务。只要队列是空的所有工人 线程阻塞,什么也不做。当任务被随机放入队列时 工作线程获取任务,完成工作并尽快睡觉 准备。这样你就可以不经重复地重复使用一个线程 创建一个新的工作线程。

当你需要停止线程时,你将一个kill对象放入队列 告诉线程关闭而不是阻塞队列。