在php中长时间运行全局计时器

时间:2011-10-28 00:58:21

标签: php timer cron

在我的应用程序中,我有多个不是实时的“游戏”。在每个游戏中,每个玩家都有一个分数。在游戏过程中,玩家可以轮流做一些动作。

但是,如果在可定制的时间内(1小时到1个月之间)没有采取任何行动,那么两个玩家将失去x点数。

我想有一个由cron作业调用的全局“计时器”。以1小时的间隔,计时器将调用每个游戏的deductPoints()功能。

deductPoints()函数中,我将执行以下操作:

deductPoints()
{
   timeSinceLastDeduction++;
   if(timeSinceLastDeduction >= frequencyOfDeduction)
   {
       deduct();
       timeSinceLastDeduction = 0;
   }
}

有没有更好的方法来完成这项任务?

2 个答案:

答案 0 :(得分:1)

当转弯发生变化时,只需将当前时间戳存储到数据库中,然后使用cron在某段时间内执行检查,如果已经过了所需的时间,则执行游戏功能。

基本上就像你有远见,但你需要在某个地方存储时间值。进入数据库或文件。

答案 1 :(得分:1)

如果您愿意存储更多数据,我建议您使用此设计。

不是每次都扣除积分(强烈依赖游戏的“状态”),而是存储玩家所采取的每一个动作。例如,我们来看看这张表:

 id | playerid | action   |         stamp
----+----------+----------+------------------------
  1 |        1 | e2 to e4 | 2011-10-27 04:00:00-04
  2 |        1 |          | 2011-10-27 04:30:00-04
  3 |        1 |          | 2011-10-27 06:00:00-04
  4 |        1 |          | 2011-10-27 07:45:00-04
  5 |        1 |          | 2011-10-27 08:00:00-04

等。等

顺便说一句,e2到e4是国际象棋的一种常见开场动作。你的游戏,我无法真正设计出来。 “动作”是可选的,但是,您只需要存储动作发生的事实来计算惩罚。 (但也可以存储额外的信息,只要你有空间这样做)。

“id”是这种情况下的代理键。在Postgresql中,DDL看起来像:

CREATE TABLE actions(
  id BIGSERIAL PRIMARY KEY,
  playerid int,
  action text,
  stamp timestamptz,
  UNIQUE(playerid, stamp));

元组(playerid,stamp)将是“真正的”主键。 “id”是代理密钥。

要查看时间戳的差异,使用窗口函数代码相对简单。 (继续使用PostgreSQL)

select playerid, time_between, id FROM
        (SELECT playerid,
                stamp - lag(stamp) OVER () as time_between,
                id FROM actions
                ORDER BY stamp)
                as ss
        WHERE playerid = 1
                AND time_between > '1 hour';

示例输出,给出前面的测试数据:

 playerid | time_between | id
----------+--------------+----
        1 | 01:30:00     |  3
        1 | 01:45:00     |  4

你根本没有cron工作。您存储了更多数据(因此更容易“撤消”操作)。如果他们愿意,您的玩家可以查看过去的动作。如果计算惩罚效率低下,那么您可以随时将分数缓存在更高的水平。

MySQL btw中没有窗口函数。但是可以在PostgreSQL,SQL Server和Oracle中使用。

编辑:如果空间是一个问题,那么你可以经常“垃圾收集”这个表定期。不过,那将是很多游戏。每行占用~48个字节(假设为“动作”)。如果你有1000个玩家,每个玩40个游戏,40个动作,你只需要384MB的数据。