1

我正在用 Flash 和 PHP 构建一个基于回合的多人游戏。有时两个用户可能同时调用同一个 PHP 脚本。该脚本旨在将一些信息写入数据库。但如果该信息已由其他用户编写,则该脚本不应运行,否则游戏将中断。如果 PHP 按顺序处理这些脚本(类似于 MySQL 将多个查询排队的方式),那么总共应该只运行一个脚本,一切都应该没问题。

但是,我发现大约 10% 的时间,两个用户的脚本都会被执行。我的理论是,服务器有时会同时收到两个用户请求来运行脚本,并且它们都运行,因为都没有检测到任何内容已写入数据库。是否有可能同时执行两个脚本?如果是这样,这个问题的可能解决方案是什么。

4

5 回答 5

2

这确实是可能的。您可以尝试在脚本的开头和结尾锁定和解锁表格。

虽然这会减慢一些请求,因为它们必须首先等待锁定的表被解锁。

于 2013-06-17T09:48:57.580 回答
1

没关系,如果是 PHP、C、Java 什么的。同时最多只能运行与 CPU(和内核)一样多的进程。如果您只有 2 个内核,可以同时运行 100 个进程。只有 2 个在运行,其余的在等待。

现在这取决于您在run下看到的内容。如果您将其视为活动,或者您还采取等待过程。其次,这取决于您的系统配置、可以等待的进程数以及您的系统规格。

于 2013-06-17T08:47:49.087 回答
1

乍一看,就像让脚本的第二个实例滚动的东西发生得不够快,有 10% 的时间......我知道你已经有某种“锁定”,就像有人告诉你的那样添加,这很棒;正如上面提到的那样,总是把这个锁放在你的脚本中,即使在调用脚本之前(也就是在父脚本中)。竞争功能/对象等也是如此......

不过请注意,我是由 google 引导到这里的,我想知道的是,如果脚本 A 未完成运行,脚本 B 是否会在 IFRAME 中运行(如果您愿意,可以在“不同的窗口”中运行);基本上你的标题有点模糊。非常感谢。

幸运的是,我们都在同一条裤子里:我正在使用 php 编写类似炉石传说的纸牌游戏(我知道,它根本不适合这个,但我只是喜欢具有挑战性的任务,(好吧,这是唯一的我熟悉的语言))。基本上,如果您不想在另一组全局事件/即时-即时-子即时滚动时触发,我必须保留多个“即时”或动作。这包括永远不要将具有事件的函数调用到相同的滚动片段中,除非我在 $_SESSION 变量上滚动一段时间,其值为 y 仅执行 sleep(1) (这发生在脚本 A 中);而 $_SESSION["phase"] == "EndOfTurnEffects" 然后继续滚动直到 $_SESSION["phase"] == "StandBy"(轮到其他玩家),我希望脚本 B 能够修改 $_SESSION["phase"]。基本上,如果脚本 B 在脚本 A 完成执行之前没有运行,我就会陷入 while 语句的无限循环......

于 2019-12-18T23:17:46.673 回答
0

这是您可以使用的 SQL 表锁定示例,以便首先获取数据库的第一个 PHP 线程将锁定表(使用锁定名称“awesome_lock_row”),直到它最终释放它。第二个线程尝试使用同一个表,并且由于锁名称也是“awesome_lock_row”),它一直等待直到第一个 PHP 线程解锁该表。

对于此示例,您可以尝试将相同的脚本作为 cron 作业同时运行 100 次,您应该会看到“update_this_data”数字字段增加到 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')" ); 
?>

希望这可以帮助。

于 2013-10-29T06:24:27.093 回答
0

他们这样做是非常合理的。查看数据库事务

简而言之,数据库事务用于控制同时访问数据库的程序之间的并发性。您启动一个事务,然后执行多个查询并最终提交事务。如果两个脚本相互重叠,其中一个将失败。

请注意,隔离级别可以进一步细粒度地控制两个(或更多)竞争脚本可以共享多少。通常,所有都可以从数据库中准备好,但只允许写入一个。因此错误将在最终提交时发生。只要所有副作用都在数据库中发生,这很好,但如果您有外部副作用(例如删除文件或发送电子邮件),这还不够。在这些情况下,您可能希望在事务期间锁定表行或设置隔离级别

于 2013-06-17T08:46:56.317 回答