如何以请求间的方式锁定部分代码


How can I lock parts of the code in an inter-request manner?

考虑一个PHP脚本(可能调用其他脚本中的函数)。我想确保它的某些部分一次只能由一个请求执行。例如:

doSomething();
doSomethingElse(); // Lock this: Can only be executed by one request at a time
yetAnotherThing();

因此,如果请求A当前"在"doSomethingElse()中,我希望在调用此函数的代码行之前对任何进一步的请求进行排队。

我在网上还没有找到解决方案,因为我说的是请求之间的锁,而不是作为同一请求的一部分执行的单独线程的锁。我使用的是Apache服务器。

您需要通过设置一个标志来指示应该发生什么或不应该发生什么来保护执行。

您可以将保护状态存储在任何其他存储中,这些存储在请求之间是持久的:数据库、会话、平面文件。。。

你能做的最基本的事情就是写一个标志文件。当文件存在时,这将排除处理doSomethingElse()的所有后续请求。但是,当文件不在时,下一个请求将再次执行doSomethingElse()


您可以使用flock()(http://php.net/manual/en/function.flock.php)或者您自己的平面文件锁定方法。仅用于概念:

添加file_put_contents(__DIR__.'/doSomethingElse.processing.flag', 'processing');

在CCD_ 6的开始处,并在函数结束时将其移除。

然后将执行打包为条件检查:

doSomething();
if( ! is_file(__DIR__.'/doSomethingElse.processing.flag')) {
    doSomethingElse(); 
}
yetAnotherThing();

建立队列

好吧,你可以扩展给定的想法,或者使用一个准备好的库/工具来完成这项工作。

为了构建一个"队列",你需要扩展锁的想法和:

  • 添加处理ID
  • 添加堆栈以查找当前最低ID进行处理
  • 以及查找和处理逻辑本身
    • 包括对所处理资源的"锁定"

队列锁定要处理的资源,并且只允许最低ID。锁通常被称为信号量。(它实际上可能是最高的ID,这取决于您的处理逻辑——它基本上是LIFO或FIFO堆栈处理。)

创建一个队列并将作业放入,然后添加一个作为cronjob或守护进程运行的工作进程。工作人员从队列中取出作业,对其进行处理,并返回状态标志为"完成"的结果。然后,您可以定期轮询队列以查看作业是否已完成。您可以为队列使用数据库,选择一个支持锁定的数据库。

while(1) {
  begin new transaction;
  remove item from queue;
  process item;
  save new state of item;
  commit;
}

不确定你要去哪里,但你有很多选择来实现它:

  • 有关基于文件的队列机制,请参阅本基本教程:http://squirrelshaterobots.com/programming/php/building-a-queue-server-in-php-part-1-understanding-the-project/

  • 您可以依赖SPLQueue并将其与锁定思想相结合。

  • PHP也支持信号量:http://php.net/manual/en/ref.sem.php

  • 然后是真正的作业队列系统,如Gearman、Beanstalk、Redis或任何消息队列,如RabbitMQ、ZeroMQ。

    • 参见齿轮手示例http://php.net/manual/en/gearman.examples-reverse.php
  • http://laravel.com/docs/5.1/queues

您可以将doSomethingElse()函数放在另一个文件中,然后可以使用

flock

http://php.net/manual/en/function.flock.php此功能用于防止同时访问。