How to save mysql connection in parent process after pcntl_fork?

As you all know, when you play a child, he gets a copy of everything, including file and network descriptors - man fork .

In PHP, when you use pcntl_fork, all your connections created using mysql_connect are copied, and this is a bit of a problem - php docs and Question SO . Common sense in this situation says to close the parent connection, create a new one and allow the child to use the old one. But what if this parent needs to create many children in a few seconds? In this case, you will create loads of new connections - one for each group of plugs.

What does this mean in code:

 while (42) { $db = mysql_connect($host, $user, $pass); // do some stuff with $db // ... foreach ($jobs as $job) { if (($pid = pcntl_fork()) == -1) { continue; } else if ($pid) { continue; } fork_for_job($job); } mysql_close($db); wait_children(); sleep(5); } function fork_for_job($job) { // do something. // does not use the global $db // ... exit(0); } 

Well, I don't want to do this - there are too many database connections. Ideally, I would like to be able to achieve this behavior:

 $db = mysql_connect($host, $user, $pass); while (42) { // do some stuff with $db // ... foreach ($jobs as $job) { if (($pid = pcntl_fork()) == -1) { continue; } else if ($pid) { continue; } fork_for_job($job); } wait_children(); sleep(5); } function fork_for_job($job) { // do something // does not use the global $db // ... exit(0); } 

Do you think this is possible?

Some other things:

  • This is php-cli script
  • I tried using mysql_pconnect in the first example, but as far as I can tell, there is no difference - the mysql server receives so many new connections. Maybe because this cli and pconnect do not work, as in mod_php. As Mark noted, pconnect in php-cli makes no sense.
+4
source share
3 answers

The only thing you can try is let your children wait for each other to finish their work. Thus, you can use the same database connection (in the absence of any problems with synchronization). But, of course, you will have many processes, which is also not very good (in my experience, PHP has quite a lot of memory usage). If several processes accessing the same database connection are not a problem, you can try to create “groups” of processes sharing the connection. Thus, you do not need to wait for the completion of each task (you can clear it when the whole group has finished), and you do not have a lot of connections.

You should ask yourself if you really need a database connection for your workflows. Why don't parents get the data and write the results to a file?

If you need a connection, you should consider using a different language for the job. PHP cli itself is not a “typical” use case (it was added in 4.3), and multiprocessing is more a hack than a supported function.

+2
source

If the child calls exec () or _exit () pretty quickly, you're fine. The problem is that the child gets up and holds copies of your file descriptors.

You can also use posix_spawn if PHP has an API for this. This may work well.

0
source

My advice (from personal experience on the same issue) is to close the connection before pcntl_fork() , then open new connections in the parent and / or child process as needed.

If you open a new connection in the parent process , you need to block the SIGCHLD signal (using pcntl_sigprocmask(SIG_BLOCK, array(SIGCHLD) ). No special care is required in child processes (unless they also start their own children, becoming parents such way.)

SIGCHLD is a signal that is received by the parent process when one of its children terminates.

During communication with the server, the MySQL client library uses nanosleep() to pause the program for some time. The sleep() functions return when time passes, but they also return to time pass if the process receives a signal while it is pausing.

When nanosleep() returns due to a signal (that is, before enough time has passed), the MySQL library is confused and reports a "MySQL server is gone" error, and the connection can no longer be used. This is a false alarm, the MySQL server is still waiting for requests, but the client code is tricked by a signal received at the wrong time.

If you are interested in receiving a SIGCHLD signal, you can block it before running the MySQL query and then unlock it (to avoid receiving it while communicating with the MySQL server.

Also read this answer and this answer I wrote to similar questions (this is information, but with more detailed information and explanations.)

0
source

All Articles