2010-05-27 22 views
15

Lea algunos textos sobre el bloqueo en PHP.
Todos ellos, principalmente, directo a http://php.net/manual/en/function.flock.php.Exclusión mutua PHP (mutex)

¡Esta página habla de abrir un archivo en el disco duro!

¿Es realmente así? Quiero decir, esto hace que el bloqueo sea realmente caro, significa que cada vez que quiero bloquear tendré que acceder al disco duro) =

¿Ya puede consolarme con una noticia deliciosa?

Editar:

Debido a algunas respuestas que tengo aquí, quiero pedir a este;
Mi secuencia de comandos se ejecutará solo por un hilo, o varios? Porque si es uno, obviamente no necesito un mutex. ¿Hay una respuesta concisa?

¿Qué es exactamente lo que estoy tratando de hacer

Pregunta de ircmaxell.
Esta es la historia:

Tengo dos servidores ftp. Quiero poder mostrar en mi sitio web cuántos usuarios en línea están en línea.
Entonces, pensé que estos servidores de ftp "PUBLICARÍAN" sus estadísticas en una determinada página de script PHP. Supongamos que la URL de esta página es "http://mydomain.com/update.php".

En la página principal del sitio web ("http://mydomain.com/index.php") mostraré las estadísticas acumulativas (usuarios en línea).

Eso es todo.

Mi problema es que no estoy seguro si, cuando un servidor ftp actualiza sus estadísticas mientras que otro lo hace también, la información se mezclará.
Al igual que cuando multi-threading; Dos subprocesos aumentan algunas variables "int" al mismo tiempo. No sucederá como se espera a menos que sincronices entre ellos.
Entonces, ¿tendré un problema? ¿Si no talvez?

Posible solución

Pensando mucho en ello durante todo el día, tengo una idea aquí y quiero que dejar su opinión.
Como dije, estos servidores ftp publicarán sus estadísticas, una vez cada 60 segundos.
Estoy pensando en tener este archivo "stats.php".
Se incluirá en la secuencia de comandos de actualización a la que van los servidores ftp ("update.php") y en la página "index.php" donde los visitantes verán cuántos usuarios están en línea.
Ahora, cuando un servidor ftp se actualiza, el script en "update.php" modificará "stats.php" con las nuevas estadísticas acumulativas.
Primero leerá las estadísticas incluidas en "stats.php", luego las acumulará y luego reescribirá ese archivo.

Si no me equivoco, PHP detectará que el archivo ("stats.php") se cambiará y cargará el nuevo. ¿Correcto?

+0

¿PHP incluso admite el enhebrado? Mirando a través de la API PHP no veo nada que parezca estar relacionado con el hilo ... – tloach

+0

Por alguna razón, pensé que PHP soporta el enhebrado, de la misma manera que ejecutará el mismo script para varios clientes simultáneamente. – Poni

+0

Así que tengo una variable estática que contendrá algunos datos, que se actualizan por varias fuentes y se alimentan a varios clientes. Esto puede suceder al mismo tiempo, por lo tanto, necesito una manera de sincronizar. – Poni

Respuesta

24

Bueno, la mayor parte de PHP se ejecuta en un espacio de proceso diferente (hay pocas implementaciones de subprocesos). El más fácil es el rebaño. Está garantizado para trabajar en todas las plataformas.

Sin embargo, si compila en soporte, puede usar algunas otras cosas como la extensión de semáforo. (Compila PHP con --enable-sysvsem). A continuación, puede hacer algo como (nota, sem_acquire() debe bloquear Pero si no puede por alguna razón, se volverá falsa.):

$sem = sem_get(1234, 1); 
if (sem_acquire($sem)) { 
    //successful lock, go ahead 
    sem_release($sem); 
} else { 
    //Something went wrong... 
} 

Las otras opciones que tiene, son MySQL user level locksGET_LOCK('name', 'timeout') , o crear uno propio usando algo como APC o XCache (Nota, esto no sería un bloqueo real, ya que las condiciones de carrera podrían crearse cuando alguien más obtenga un bloqueo entre su cheque y la aceptación del candado).

Editar: Para responder a su pregunta editado:

Todo depende de la configuración del servidor. PHP puede ejecutarse en varios subprocesos (donde cada solicitud es servida por un hilo diferente), o puede ejecutarse en multiproceso (donde cada solicitud es servida por un proceso diferente). Todo depende de la configuración de su servidor ...

Es MUY raro que PHP sirva todas las solicitudes en serie, con un solo proceso (y un hilo) atendiendo todas las solicitudes. Si está utilizando CGI, entonces es multiproceso por defecto. Si está utilizando FastCGI, es probable que sea multiproceso y multihilo. Si está utilizando mod_php con Apache, entonces depende del tipo de trabajador:

  1. mpm_worker será a la vez multi-proceso y multi-hilo, con el número de procesos dictados por la variable ServerLimit.
  2. prefork será multi-proceso
  3. perchild será multi-proceso, así

Editar: Para responder a su segunda pregunta editado:

Es bastante fácil. Guárdelo en un archivo:

function readStatus() { 
    $f = fopen('/path/to/myfile', 'r'); 
    if (!$f) return false; 
    if (flock($f, LOCK_SH)) { 
     $ret = fread($f, 8192); 
     flock($f, LOCK_UN); 
     fclose($f); 
     return $ret; 
    } 
    fclose($f); 
    return false; 
} 

function updateStatus($new) { 
    $f = fopen('/path/to/myfile', 'w'); 
    if (!$f) return false; 
    if (flock($f, LOCK_EX)) { 
     ftruncate($f, 0); 
     fwrite($f, $new); 
     flock($f, LOCK_UN); 
     fclose($f); 
     return true; 
    } 
    fclose($f); 
    return false; 
} 

function incrementStatus() { 
    $f = fopen('/path/to/myfile', 'rw'); 
    if (!$f) return false; 
    if (flock($f, LOCK_EX)) { 
     $current = fread($f, 8192); 
     $current++; 
     ftruncate($f, 0); 
     fwrite($f, $current); 
     flock($f, LOCK_UN); 
     fclose($f); 
     return true; 
    } 
    fclose($f); 
    return false; 
} 
+0

Espacio de proceso diferente aún puedo tener una variable estática (también conocida como singleton) que se comparte entre todos los clientes: ¿cómo es posible? – Poni

+0

Este nivel de usuario MySQL bloquea es bueno, pero requiere una conexión TCP y una máquina/instancia MySQL. Mejor utilizar el bloqueo basado en archivos ... ¡Gracias, sin embargo! – Poni

+0

No puede compartir una variable en varias instancias de php. Bueno, podrías hacerlo serializarlo y almacenarlo en una tienda global (como APC, memcached, MySQL, etc.). Pero cada "cliente" crearía su propia instancia. ¿Qué estás tratando de hacer exactamente? – ircmaxell

-2

PHP no es compatible con multihilo, cada solicitud (y por lo tanto cada script PHP) se ejecutará en un solo subproceso (o incluso proceso, dependiendo de la forma en que ejecute PHP).

+0

PHP admite multithreading, puede hacerlo fácilmente usando HTTP asincrónico. – Slawek

+0

Espera, HTTP asincrónico es del lado del cliente, eso no quiere decir que el lado del servidor se ejecute en subprocesos múltiples (cada solicitud asincrónica se ejecuta como un script PHP con un solo hilo). – Daff

+0

pcntl_fork te permitirá hacer subprocesos múltiples, me pregunto por qué nadie lo menciona. – CodeReaper

0

Sí, eso es cierto, ya que PHP es ejecutado por Apache, y Apache puede organizar los hilos de ejecución como considere mejor (vea el modelo de varios trabajadores). Entonces, si desea acceder a un recurso de uno en uno, puede bloquearlo (lo que es bueno si está trabajando con tareas cron, por ejemplo), o depende del mecanismo de transacción de la base de datos, las funciones ACID y el bloqueo de recursos de la base de datos. si está tratando con datos.

0

Si necesita enhebrar, está utilizando el lenguaje equivocado, en serio.

+8

Sí, y no necesito enhebrar. Necesito t o saber que un objeto estáticamente compartido (digamos un contador de visitas de tipo int) no será accedido por más de un hilo a la vez. Me temo que PHP lo hará, porque ASUMO que el script PHP se ejecuta en más de un hilo en el servidor. ¿Lo hará o no? Esa es la pregunta. – Poni

1

La pregunta es: ¿Dónde almacenará las estadísticas que los servidores FTP están presionando con POST en su archivo update.php? Si es un archivo local, entonces ircmaxell en la segunda publicación te ha respondido. También puede hacer esto con un mutex: las funciones del semáforo. Otra solución es usar la tabla MyISAM de MySQL para almacenar las estadísticas y usar algo como update info_table set value = value + 1. Debe bloquear la tabla y serializar sus solicitudes, y no tendrá problemas.

0

¿Por qué no hace que el archivo de actualización escriba en un nombre de archivo basado en la dirección IP del servidor ftp entrante? Y el archivo stats php simplemente lee y agrega los contenidos numéricos de ambos archivos juntos.