在 Windows 上分叉 PHP
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2458005/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Forking in PHP on Windows
提问by Doug Kavendek
We are running PHP on a Windows server (a source of many problems indeed, but migrating is not an option currently). There are a few points where a user-initiated action will need to kick off a few things that take a while and about which the user doesn't need to know if they succeed or fail, such as sending off an email or making sure some third-party accounts are updated. If I could just fork with pcntl_fork()
, this would be very simple, but the PCNTL functions are not available in Windows.
我们在 Windows 服务器上运行 PHP(确实是许多问题的根源,但目前还不能选择迁移)。在某些情况下,用户启动的操作需要启动一些需要一段时间并且用户不需要知道它们是成功还是失败的事情,例如发送电子邮件或确保某些事情第三方帐户已更新。如果我可以只使用 fork pcntl_fork()
,这将非常简单,但是 PCNTL 函数在 Windows 中不可用。
It seems the closest I can get is to do something of this nature:
似乎我能得到的最接近的是做这种性质的事情:
exec( 'php-cgi.exe somescript.php' );
However, this would be far more complicated. The actions I need to kick off rely on a lot of context that already will exist in the running process; to use the above example, I'd need to figure out the essential data and supply it to the new script in some way. If I could fork, it'd just be a matter of letting the parent process return early, leaving the child to work on a few more things.
然而,这会复杂得多。我需要启动的操作依赖于运行过程中已经存在的大量上下文;要使用上面的示例,我需要找出基本数据并以某种方式将其提供给新脚本。如果我可以分叉,那只是让父进程提前返回,让子进程处理更多事情的问题。
I've found a few people talking about their own work in getting various PCNTL functions compiled on Windows, but none seemed to have anything available (broken links, etc).
我发现一些人在谈论他们自己在 Windows 上编译各种 PCNTL 函数的工作,但似乎没有任何可用的东西(断开的链接等)。
Despite this questionhaving practically the same name as mine, it seems the problem was more execution timeout than needing to fork. So, is my best option to just refactor a bit to deal with calling php-cgi, or are there other options?
尽管这个问题实际上与我的名字相同,但问题似乎是执行超时而不是需要分叉。那么,我最好的选择是稍微重构一下以处理调用 php-cgi,还是有其他选择?
Edit: It seems exec()
won't work for this, at least not without me figuring some other aspect of it, as it waits until the call returns. I figured I could use START
, sort of like exec( 'start php-cgi.exe somescript.php' );
, but it still waits until the other script finishes.
编辑:这似乎exec()
不起作用,至少在我没有弄清楚它的其他方面的情况下不会起作用,因为它会等到调用返回。我想我可以使用START
,有点像exec( 'start php-cgi.exe somescript.php' );
,但它仍然要等到另一个脚本完成。
采纳答案by jah
how about installing psexecand use the -d
(don't wait) option
exec('psexec -d php-cgi.exe somescript.php');
回答by Razvan Tanase
PSTools are a good patch in, but I'll leave this here:
If your server runs windows 10 and it has the latest updates, you can install a Linux subsystem, which has its own Kernel that supports native forking.
This is supported by Microsoft officially.
PSTools 是一个很好的补丁,但我会留在这里:
如果你的服务器运行 Windows 10 并且它有最新的更新,你可以安装一个 Linux 子系统,它有自己的内核,支持本机分叉。这是微软官方支持的。
Here's a good guideon how to do it.
这是有关如何执行此操作的好指南。
Once you've installed the subsystem itself, you need to install php on the subsystem.
一旦你安装了子系统本身,你需要在子系统上安装 php。
Your windows "c:\" drive can be found under "/mnt/c", so you can run your php from the subsystem, which supports forking (and by extension the subsystem's php can use pcntl_fork).
您可以在“/mnt/c”下找到您的 Windows“c:\”驱动器,因此您可以从支持分叉的子系统运行您的 php(并且通过扩展子系统的 php 可以使用 pcntl_fork)。
Example: php /mnt/c/xampp/htdocs/test.php
例子: php /mnt/c/xampp/htdocs/test.php
If you want to run the subsystem's php directly from a windows command line you can simply use the "wsl" command.
如果您想直接从 Windows 命令行运行子系统的 php,您可以简单地使用“wsl”命令。
Assuming you're running this from under "C:\xampp\htdocs\"
Example: wsl php main.php
假设您从“C:\xampp\htdocs\”下运行此
示例:wsl php main.php
The "wsl" command will resolve the path for you, so you don't need to do any dark magic, if you call the command under c:\xampp\htdocs, the subsystem will resolve it as "/mnt/c/xampp/htdocs/".
“wsl”命令会为你解析路径,所以你不需要做任何黑魔法,如果你调用c:\xampp\htdocs下的命令,子系统会解析为“/mnt/c/xampp /htdocs/”。
If you're running your server as an apache server, you don't really need to do anything extra, just stop the windows apache server and start the linux one and you're done. Obviously you'll need to install all the missing php modules that you need on the subsystem.
如果您将服务器作为apache 服务器运行,则您实际上不需要做任何额外的事情,只需停止 windows apache 服务器并启动 linux 服务器即可。显然,您需要在子系统上安装您需要的所有缺失的 php 模块。
回答by Frank Forte
You can create a daemon/background process to run the code (e.g. sending emails) and the request would just have to add items to the queue, let the deamon do the heavy lifting.
您可以创建一个守护进程/后台进程来运行代码(例如发送电子邮件),并且请求只需将项目添加到队列中,让守护进程完成繁重的工作。
For example, a file send_emails.bat:
例如,文件send_emails.bat:
cls
C:\PHP533\php.exe D:\web\server.php
exit
open windows task scheduler, and have the above send_emails.bat run every 30 minutes. Make sure only one instance runs at a time or you might run each task in multiples, or send each email twice. I say 30 minutes in case something breaks temporarily (memory issues, database unavailable, etc), it will re-start every 30 minutes rather than having a never ending process that just stops. The following is a skeleton daemon... not complete or tested I am just typing out an example:
打开windows task scheduler,每30分钟运行一次上面的send_emails.bat。确保一次只运行一个实例,否则您可能会多次运行每个任务,或者每封电子邮件发送两次。我说 30 分钟,以防出现临时中断(内存问题、数据库不可用等),它将每 30 分钟重新启动一次,而不是一个永无止境的进程就停止。以下是一个骨架守护进程......不完整或测试我只是打出一个例子:
<?php
set_time_limit(60*30); // don't run
$keepgoing = true;
$timeout = time()+ 60*29; // 29 minutes
while(time() < $timeout)
{
// grab emails from database
$result = $db->query('select subject, body, to_email FROM email_queue');
if($result->num_rows == 0)
{
sleep(10); // so we are not taxing the database
}
else
{
while($row = $result->fetch_assoc())
{
// send email
}
}
}
exit;
?>
Finally you just need the request to add the item to the queue in a database, and let the daemon handle the heavy lifting.
最后,您只需要将项目添加到数据库中的队列的请求,并让守护程序处理繁重的工作。
$db->query('insert into email_queue(to,subject,body) values ('[email protected]','important email','<b>html body!</b>');