我正在用Flash和PHP构建一个回合制多人游戏。有时两个用户可能同时调用同一个PHP脚本。这个脚本的目的是将一些信息写入数据库。但是如果其他用户已经编写了这些信息,那么脚本就不应该运行,否则游戏就会崩溃。如果PHP按顺序处理这些脚本(类似于MySQL对多个查询进行排队),那么总共应该只运行一个脚本,一切都应该很好。
然而,我发现大约10%的时间,两个用户的脚本都被执行。我的理论是,服务器有时会在完全相同的时间接收到运行脚本的两个用户请求,并且它们都运行,因为它们都没有检测到已向数据库写入任何内容。有没有可能两个脚本是同时执行的?如果是这样,有什么可能的解决方案。
这确实是可能的。您可以尝试在脚本的开头和结尾锁定或解锁表。
虽然这会减慢一些请求的速度,因为它们必须首先等待被锁定的表被解锁。
不管它是PHP, C还是Java。在同一时间,只能运行最大进程数,因为您有cpu(和内核)。可以同时运行100个进程,如果你只有2个核心。只有两个在跑,其余的在等。
现在它取决于你在下看到的运行。如果你认为它是主动的或者你也认为它是等待过程。其次,这取决于您的系统配置、有多少进程可以等待以及您的系统规格。乍一看,好像什么保持脚本的第二个实例滚动只是没有发生得足够快,10%的时间…我知道你已经有了某种"锁",就像别人告诉你的那样,这很好;正如上面提到的,总是把这个锁放在脚本的第一件事,如果不是在调用脚本之前(也就是在父脚本中)。对于相互竞争的函数/对象等也是如此。
只是一个说明,虽然,我是由谷歌执导这里,我想知道的是,如果脚本B将运行在IFRAME(所以在一个"不同的窗口",如果你愿意),如果脚本a没有完成运行;基本上你的标题有点模糊。非常感谢。
幸运的是,我们在同一条裤:我正在使用php编程一个类似炉石传说的卡牌游戏(我知道,这并不适合这个,但我只是喜欢具有挑战性的任务,(好吧,这是我唯一熟悉的语言))。基本上,我必须保持多个"瞬间"或动作,如果你喜欢触发,而另一组全局事件/瞬间-瞬间-子瞬间滚动。这包括永远不要将具有事件的函数调用到相同的滚动代码段中,除非我在值为y的$_SESSION变量上滚动一会儿,该变量只执行sleep(1)(发生在脚本a中);而$_SESSION["phase"]=="EndOfTurnEffects",然后继续滚动,直到$_SESSION["phase"]=="StandBy"(其他玩家的回合),我希望脚本B移动$_SESSION["phase"]。基本上,如果脚本B没有在脚本A完成执行之前运行,我就会陷入while语句的无限循环中……
他们这样做很有可能。查看数据库事务
简单地说,数据库事务用于控制同时访问数据库的程序之间的并发性。您启动一个事务,然后执行多个查询,最后提交事务。如果两个脚本相互重叠,其中一个将失败。注意,隔离级别可以进一步细粒度地控制两个(或更多)相互竞争的脚本可以共享多少资源。通常都允许从数据库准备,但只允许写入一个。因此错误将在最后提交时发生。只要所有副作用都发生在数据库中,这是可以的,但如果有外部副作用(例如删除文件或发送电子邮件),这就不够了。在这些情况下,您可能希望在事务期间锁定表或行,或者设置隔离级别。
这是一个SQL表锁定的示例,您可以使用它,以便第一个获取DB的PHP线程将锁定表(使用锁名"awesome_lock_row"),直到它最终释放它。第二个线程尝试使用同一个表,因为锁的名称也是"awesome_lock_row"),所以它继续等待,直到第一个PHP线程解锁了表。
对于本例,您可以尝试将同一个脚本作为cron作业并发运行100次,您应该看到"update_this_data"number字段增加到100。如果表没有被锁定,所有并发的100个线程可能首先会同时看到"update_this_data"为0,最终结果将是1而不是100。
<?php
$db = new mysqli( 'host', 'username', 'password', 'dbname');
// Lock the table
$db->query( "DO GET_LOCK('awesome_lock_row', 30)" ); // Timeout 30 seconds
$result = $db->query( "SELECT * FROM table_name" );
if($result) {
if ( $row = $result->fetch_object() )
$output = $row;
$result->close();
}
$update_id = $output->some_id;
$db->query( UPDATE table_name SET update_this_data=update_this_data+1 WHERE id={$update_id} );
// Unlock the table
$db->query( "DO RELEASE_LOCK('awesome_lock_row')" );
?>