发新话题
打印

[方法技巧] php实现多线程技术

php实现多线程技术

我们知道PHP本身是不支持多线程的, 但是我们的WEB服务器是支持多线程的. : {9 o9 b/ {* o
& ~1 e% Z, ]: _

5 ^9 `, i+ c2 r! ?& r+ L8 T也就是说可以同时让多人一起访问. 这也是我在PHP中实现多线程的基础. - H2 o, D+ t9 V* K1 i8 N6 ^, ?

3 P, p0 p7 U% o
, b9 f7 `2 u1 V( D* |* t3 ^% e假设我们现在运行的是a.PHP这个文件. 但是我在程序中又请求WEB服务器运行另一个b.PHP
8 K+ M9 s/ A. ?+ I: Z: R3 }4 [, i& ^" t4 V- c
( |4 v4 ~8 H" B; F0 ]; |3 }
那么这两个文件将是同时执行的. ) k  a- ]: Y: s4 |" u4 W
% {& P9 T9 r7 J
. z& r4 K: _( c7 b+ ~% c3 G" W
(PS: 一个链接请求发送之后, WEB服务器就会执行它, 而不管客户端是否已经退出)
1 c* X; i0 k" ]; I! l! O- J: \8 x) g8 Y0 T# z. g% V  y5 a
; g8 S* m9 }$ x
有些时候, 我们想运行的不是另一个文件, 而是本文件中的一部分代码.该怎么办呢? " X* r1 u- X0 a3 f
% \5 F! K9 o6 ?1 l

5 J/ k0 d5 e; K其实可是通过参数来控制a.PHP来运行哪一段程序.
/ M5 D0 H8 H" w7 v" \2 M, t
0 S. C8 g, q+ `( t) B
* h- c  ?: L# o6 {& w下面看一个例子: . c+ P  A2 e. l! C; {) Z0 P

) n# K$ H! y, f) F1 [
. z. H  L" N6 E* C( S/ `//a.PHP . `, ?" J, a* j+ q! u

1 t: y5 ^% f( e; W5 O: w& J( d& b' W' J! d* J* n6 E
PHP代码:-------------------------------------------------------------------------------- # Z  y0 H5 R: B* }2 ?. `

+ x! z  K0 g3 |& O; j! G
9 q: z$ F* X4 m: O4 |( Z<?PHP ! t& s* Q0 b6 O7 z
3 w3 M" N, N5 a- e+ D! z+ \) }
function runThread() # ~9 I8 A. r; s

- x# S5 \" a" O" W+ K{
$ ~4 Z; }4 C5 E1 n# a" X1 e, y0 G
& I) d7 a$ S0 a$ R7 E2 x7 Z+ D* x$fp = fsockopen(localhost, 80, $errno, $errmsg); ' L! |1 p( }) \  q- i/ h
9 }6 }: W% ^8 X. W, u
( u" W. |- A. w: ~" a/ E+ p
fputs($fp, "GET /a.PHP?act=b
, M, ?2 D/ E8 I) E! D6 l4 s( p, a& T6 x% A4 O+ ]  K: }* e
"); //这里的第二个参数是HTTP协议中规定的请求头 , p9 ~; @+ p3 d& P2 }4 e( l
0 g& z5 r( D5 C/ B2 |; V! Q
//不明白的请看RFC中的定义
( ]: g6 t) L3 X! o: e- l3 G, N1 l
5 ?" s5 n7 s( D% ^7 D. i+ f  G+ E; b8 D. u
fclose($fp);
6 A1 y1 _' U, X5 d; M
) T; h0 h" i& y( V! t% z/ |& E$ O, u}
- C1 t. c1 h( I# h
# f6 q- {" u  s: s  A( R; k/ _: L0 z( c) e' B* U6 d
function a()
9 b0 d4 E- O( r- `: Y
1 [0 u; r; C6 k8 C# s8 G. f{ - D8 ?% x' p- a2 _( R% a

4 l3 f% N! L7 k4 X7 [( L$fp = fopen(result_a.log, w); 0 `4 b" n  Z  Y8 T

; u: @. W0 u  F; F% e! Tfputs($fp, Set in . Date(h:i:s, time()) . (double)microtime() . "' B7 V: |+ a: @  F
");
; j# U& U" q8 z* u. B5 f/ X# A
" H. q& i" C+ p: `2 E. R  `' l
" R  Q8 |2 g* ]2 p5 O8 F+ Gfclose($fp);
& s* H! A# \- ~7 {) [
1 G1 B4 t7 j' R6 F' N$ X8 ~} 4 }0 W2 k' J: m$ {# g5 {6 ^9 T

) E! h+ n/ y  `2 m7 C0 J* o  _
7 V  B  Y; ?8 W- O) d' W$ Nfunction b()
# P: J! j0 c2 Y4 E0 ~; h+ `
% a6 Q3 ?3 ^$ l$ y" S. P7 S{
% ~% g3 y9 x- H" d+ \6 w$ c
4 D6 A* Q0 W1 b( O; ^/ ?+ U$fp = fopen(result_b.log, w);
- q. E1 Z- r* ~% V. V
3 j9 i" E0 L$ H6 d* B; k* v" A5 i1 Ofputs($fp, Set in . Date(h:i:s, time()) . (double)microtime() . "
- c, E8 F) m0 q( j1 Y; m8 W/ E");
9 A- K3 r- d/ [  U5 Q1 w, n3 @* f, a  `3 C/ X
7 x  @& y* S& d4 [6 y( X9 b; z
fclose($fp);
" `( s+ I) d- f, L, g1 k+ x7 d/ g0 p3 O
8 i8 z( X' b& h7 p9 t0 `} 2 ^& t8 V1 [  k2 }. F+ `: {

. U) f# R. G5 E2 x
6 e; A! W2 ^! A' v) Wif(!isset($_GET[act])) $_GET[act] = a;
6 g! F0 R& u' L' y
2 S& j  N4 c' k- {$ u9 c
- p; t& L: h( Q9 l2 Lif($_GET[act] == a) 6 ?2 [' \' u( y, W0 Y( ]  n* S# _( `

9 a" `3 @% [; q. _) k( p. _8 D{
. K/ [) Z# U1 a# a9 Y4 C' z# `5 L) I& o; w
runThread(); ! m0 B2 F+ N2 ]$ `6 Q+ D0 A

- a; @! C2 z+ l5 ]a();
/ C' @$ c  z, t* d. k
* V2 W: [6 u  ^& Q1 }} ( I+ x1 \' ~" E/ n4 e
9 X: Q( z$ W) U0 N
else if($_GET[act] == b) b(); - u4 c1 X+ T+ j' C' B! |1 w

7 P6 d$ x. G" L" \?>
/ B7 z0 S9 C7 e: r# v, Z" z- Y. a6 C$ H
, d2 |. b+ y$ x1 T% b0 G! B
--------------------------------------------------------------------------------
7 C) h" C+ w3 R( G2 X+ T
+ j5 G% C, H  D* h8 w
6 b  q! s0 B( t. O, R6 t+ O3 x; l
, l7 G- y& V7 K打开result_a.log 和 result_b.log 比较一下两个文件的中访问的时间. 大家会发现, 这两个的确是在不同线程中运行的.
, J) D4 p' _  r6 h  L  [9 b+ R9 o
有些时间完全一样. 5 E4 C) d  z, M$ r( `! j: b
; S+ S! D6 P2 N# _2 J$ t  }. @

( R" p/ r: B. K! N; p; |上面只是一个简单的例子, 大家可以改进成其它形式.
4 b5 }, C& q2 \* X- Q% n2 Q- T' K1 f( y
; X! j- W3 c3 l1 M  L# r
/ C7 J" e9 w; i
既然PHP中也能多线程了, 那么问题也来了, 那就是同步的问题. 我们知道 PHP本身是不支持多线程的. 所以更不会有什么像 , n# [/ ?+ d1 X$ @0 D% j8 i7 l& ~

7 b4 i0 T4 o9 M$ a9 B) |9 C2 X
; k$ L, ^8 u5 g# h0 [5 k1 aJava 中synchronize的方法了. 那我们该如何做呢. ; D9 K! U0 t" ]7 H! F8 g/ Z6 L
% ]2 ]9 A, R6 p. Q5 D4 m- m
' L4 S2 `; b0 ^! [
1. 尽量不访问同一个资源. 以避免冲突. 但是可以同时像数据库操作. 因为数据库是支持并发操作的. 所以在多线程的PHP中
4 ^, S; @. t( C. Z+ w
- s) z/ ^+ Y! G' b+ e# v
6 G6 C  ^- n' M' P1 O1 ]- N3 w# }不要向同一个文件中写入数据. 如果必须要写的话, 用别的方法进行同步.. 如调用 flock对文件进行加锁等. 或建立临时文件 $ S6 M$ O, y' p, G
5 e& X  H6 D* ?( _/ p, K' J
* t/ ^% r# ?+ T1 I( t: G
并在另外的线程中等待这个文件的消失 while(file_exits(xxx)); 这样就等于这个临时文件存在时, 表示其实线程正在操作 , ]3 j2 y8 N8 W. W" m

9 U7 x6 D  o- k, b3 ^. Z  ]+ a. M
" z5 b4 p) P6 Y/ {) Q7 \如果没有了这个文件, 说明其它线程已经释放了这个. , s3 K8 K/ a7 q3 r7 p0 C& J) S5 I* M

$ |- e0 P2 O! ]: ~9 w( s3 ~" X: ]( u& u. W, a0 A
2. 尽量不要从runThread在执行fputs后取这个socket中读取数据. 因为要实现多线程, 需要的用非阻塞模式. 即在像fgets这
* a0 p. d+ A7 ?0 V8 V3 Z# Y% T7 L7 B' U8 n7 U
* J6 x9 x9 A" R; p+ ~: k& \. s
样的函数时立即返回.. 所以读写数据就会出问题. 如果使用阻塞模式的话, 程序就不算是多线程了. 他要等上面的返回才执行   E6 \, N: Y: x6 N! }+ g2 v8 ^6 T

. S4 e& ^8 ]/ e- [, P0 n. v1 G8 c+ F5 a; y' D: q, Q$ s
下面的程序. 所以如果需要交换数据最后利用外面文件或数据中完成. 实在想要的话就用socket_set_nonblock($fp) 来实现. 0 {9 M; U, W5 y1 \; Q
+ q: j' W! {! E
( O/ }& i4 h9 j6 J9 z/ ^- i1 \
; m  L% [+ U; F/ i& G
说了这么多, 倒底这个有没有实际的意义呢? 在什么时候需要这种用这种方法呢 ?
! }8 S0 V( X; z/ ~- g1 P, V
2 h3 B" ^1 \" v' [
5 A( F1 ?8 }8 r) I( w答案是肯定的. 大家知道. 在一个不断读取网络资源的应用中, 网络的速度是瓶颈. 如果采多这种形式就可以同时以多个线程对不同的页面进行读取.
发新话题