2 ~( g T9 G' C w4 \9 ^' D
爬虫(七十)多进程multiprocess(六十一)
3 X' ^; Z# h, b1 w5 A w# J3 Y; ~Python中的multiprocess提供了Process类,实现进程相关的功能。但是它基于fork机制,因此不被windows平台支持。想要在windows中运行,必须使用if __name__ == '__main__:的方式,显然这只能用于调试和学习,不能用于实际环境。 另外,在multiprocess中你既可以import大写的Process,也可以import小写的process,这两者是完全不同的东西。这种情况在Python中很多,请一定要小心和注意。 下面是一个简单的多进程例子,Process类的用法和Thread类几乎一模一样。 - + w! O, [; d1 \" Y5 U5 l
' _! u# ]/ J M% J+ \
import os5 I. P' ?" @: {5 k& \
: Z, Q) K- |9 _& ]& v: M
' o' w* {: U; o+ S; P; k6 l. ^( ~5 ` R5 b ~6 t
import multiprocessing
/ z1 ?5 Q, k% P4 o8 ~. t# k
# o8 z! F: m6 _! `4 {* v: t# o6 s
$ p5 `# \9 x: a. E5 B# k& ?+ y) M% {9 c: e# g' h, A0 j, Y
) k' Q5 q9 [5 m+ |: i
4 q: M0 r7 u" a0 |" }
+ i: P0 [. U i& a7 ~8 T! [( V' |# @! b% j
def foo(i):6 R( F& y& j3 |2 \/ p
/ A& X" ?8 s; \. Y c' e9 `6 w- 9 Q2 A0 I1 x) B7 B& L* Z
5 X- p2 [$ ^2 H. a& [3 j9 O # 同样的参数传递方法2 V/ R, K. S( ~, J+ ^& ?
r; ?* o0 k0 c6 n- l' H
2 V# v0 Y3 C6 P$ E6 m! A w) ~& {! R
print("这里是 ", multiprocessing.current_process().name)" J l- V: J9 `6 m6 B x+ I
; H- [+ U. T/ j* V3 J7 ~
( S4 _0 \( ?; z" l
: y$ h) ~3 X7 Z print('模块名称:', __name__)4 I7 w/ I# W& m/ G; N
1 q$ c- _3 t$ u- d( H4 E2 u
8 }1 h5 K- P/ {2 F* I$ [; B/ |0 ?/ Y4 s' @. F& |* S* J. h
print('父进程 id:', os.getppid()) # 获取父进程id* G9 c/ ~) ~" q! t" ?2 e5 D
5 p, ^0 g) e1 Z A/ a
/ O3 }! E1 ]/ c* Q( x: W
5 j! m; U! I+ A2 {* w t print('当前子进程 id:', os.getpid()) # 获取自己的进程id4 O0 p# }1 y4 c" H
! n! G+ ~% @6 Q+ j
2 [, [9 A; Y0 b. _ x% ~0 V! H. }9 o/ G0 E) P0 z) Z+ Y& |+ `. U$ l
print('------------------------')
9 }: T1 U4 Q+ W" N9 M/ F7 D1 L4 i. y2 Q8 \- p' u
. Q$ l5 t* E0 N4 B" r8 j' P1 q+ Q# E% c: a; C
# m. O4 }. R" J; }
, I2 @! \$ U' x
4 w; F- O: w0 ^4 n, t8 P$ e; E7 k+ ~( p8 d, K; f
if __name__ == '__main__':
0 {1 M- N# A z! {! J# g7 D6 B4 r) _9 f7 Q' J$ _
6 V$ a2 ^% _) C* [' V/ A& t
- M1 S- o1 f' }
1 e2 r, ] D; k% a8 W! A/ [! C4 V8 ^ `) _1 M( I8 s' V! t J3 \
- 1 g# g) ?* e6 e* t
1 @# H7 X. }/ \0 {0 C+ x0 C' j
for i in range(5): @4 Z4 B7 h/ W, j# k! ~
, N* L4 N7 H* G# R+ r
7 q3 T+ x4 U* ?& t* N7 f% [$ g. `/ s4 l
p = multiprocessing.Process(target=foo, args=(i,))7 @, i( g# F2 c' Q, g
" @$ |6 Y2 V! E
- 2 H: N# b$ }: i, P# L1 I
( S' n6 h3 G8 p
p.start()% Q& C& e5 _; L$ H) t
) J, S5 o6 b: \9 h; \
0 e8 P) `/ X x+ u, `1 ]. ~
运行结果:
( X2 [# \( H& v% g6 ^. L, |% |$ T" }+ @$ M5 g
这里是 Process-24 ~2 n4 O u( f( ]2 C
9 u7 f3 O& h, A
2 K- E* J( T& @+ A! m! `! H }4 l4 L2 V' A' u: [5 h" ]
模块名称: __mp_main__* j+ |2 m2 k$ }
# k. R, k0 T' j. T3 z; @
& [4 ?1 V7 v& y% g7 _, \# E- Q
8 J& M+ O4 _4 W( _) ^' ]: B' d父进程 id: 8807 {) P6 u: f7 J2 @! V
$ f$ O5 S& \$ w, I+ x4 ?- : E! @! w: g6 o% o% F( G; f1 w
0 ^8 I1 c, s) w+ _( l+ M
当前子进程 id: 5260
$ @% k" F0 u1 b. M7 Q$ f7 B1 d, q2 c+ \' b2 c/ H% R
- # u' f! `! c5 ^, l
6 _. C4 D( v0 \, O- O5 u" e
--------------: ^) q7 Z* i+ `. n8 R
& |1 X6 Y- C5 |3 y
- u/ q, T& q3 U
7 H! \& } C t( T
这里是 Process-3
5 i0 d- ~! q6 N7 v) G7 y
/ z. N/ R. l( h
2 @; h3 j: M2 @. l/ D8 g: s9 I0 G% g- `
模块名称: __mp_main__
9 a5 A. @0 q7 [- _
. o; |) `: M2 y3 ^3 j+ k- m2 C- - _* u5 D# x! R: _* l! g2 E4 l
g% L v5 T% I) H
父进程 id: 880
8 ]8 V1 P- V9 ?* l" Q2 \0 Z( P) t
( n! e6 x2 T) }* z - 7 v+ c7 P6 }. i4 y" v
8 w8 J/ D( e& Z& x7 W4 g! c8 y1 g
当前子进程 id: 4912
/ I4 n$ p% j1 u+ ]; _4 E/ Z
% b- C* L8 F3 s* C, R [6 O2 T - * S, T% P7 Q9 i# y/ J
( V8 a* w! f/ ~# b5 Z. D9 i2 r
--------------+ Q. E/ s0 M1 b3 ^3 o- M) [ L2 M
3 G) c2 L, X* U5 E9 o a% s% x
- ' \' m; ]' f: |% p/ Q# I2 o
8 r; r, X/ r0 I8 z1 v- p4 d这里是 Process-4; [6 d/ {# H' `3 I
) L; z, D3 Q8 s$ z8 l8 I" m - 9 m; e9 a( B$ j' I4 g
' D( V/ {5 c# ]$ Y; |
模块名称: __mp_main__9 k9 b: _, N* V, T }' h1 r
! @1 w j5 ~7 Q/ H8 \' ^ - ! j9 S( F) m l
. |9 _! [7 u. Y8 w* J父进程 id: 8808 M" T1 E \$ L z
; [$ r5 Z2 p* n4 u/ k
- . P0 v6 t$ ?0 X1 \6 K5 f) G
+ N. K0 }; f9 u* J当前子进程 id: 51769 ]; e/ Q9 N' X5 }6 ]
+ |" Y1 J+ s; K0 r2 @. K- Y( C
- $ X, `. I# Y% f1 p
; `+ L1 W0 C0 m6 ^6 A: B
--------------" C# q! w" {9 @$ E
. u, z2 {8 h5 V. K& _, O. i
7 A- Z8 p% }% L) z/ ]7 G
+ }+ a6 ^! x$ L; ~; m3 L这里是 Process-1
: ]( s$ s# f' Q5 U: j! O! K: M9 D7 b- V" w& l [
2 P& A5 f$ q6 s# U; \
9 e5 X s; J) \9 ~# q7 [' n模块名称: __mp_main__
: h% s& {$ j) B2 G' y8 e, b* _1 @& i+ w8 ?7 {% @ K- F% H; a
* q2 D3 r' F- x$ }" i
$ g+ h+ s* p6 b* Y9 G4 \. i7 ]: ~! N父进程 id: 8805 P# J; `! U* i* W$ {. _) J
o W/ i. }( F* x! C3 t- }
- 0 T: K0 W. g4 V: Q- P
$ Q2 _1 U6 f+ |
当前子进程 id: 5380
+ d# }4 v! ?% V4 b% _! u: L* ]( n5 e* E' }7 |# W' E! b1 q
- 0 ~3 _5 O% h! v: Z x
2 z) E$ @& ]7 X6 }! F4 R [--------------) B/ j3 _, ?4 h
# _' Y/ S0 p2 T# q1 P. S0 E. Q
- % @3 [! V; F3 e* a, M
' R" W& @, I+ U: u这里是 Process-5
3 M& ^, g2 q, T$ G# X
3 m. X5 t9 x1 l2 B9 e) o5 `; a - 0 _1 f) u# g0 d, Z# e: p
8 p- T | P: J2 E* Z& r模块名称: __mp_main__
) |/ ], `$ ^. w" ^0 T6 q# x, `; j) ^) Q& ^2 j9 N: L3 ` S& c
- % e0 S7 h$ ?: s: a, M' f% M
% Q) }" H" {( G, L/ E
父进程 id: 880( n2 b+ ?1 z4 d- g/ L
& A' f+ s' V% I8 @) v
- % P9 q% k" S- q% R6 G! ]* w
% @9 h0 J" k3 V8 t; o6 U! U8 Q* }" K
当前子进程 id: 3520
& q. Q+ D1 @1 R' E
" T9 H X8 @1 P) L K
: K2 T. z% L, N9 Z, l
! P5 U+ r, ?+ s, D$ N* h--------------
) j) C4 E' ~ y$ E K. a/ q- ]1 d# W. s
7 o# f1 W. o1 x# g5 _/ \ 1. 进程间的数据共享在Linux中,每个子进程的数据都是由父进程提供的,每启动一个子进程就从父进程克隆一份数据。 创建一个进程需要非常大的开销,每个进程都有自己独立的数据空间,不同进程之间通常是不能共享数据的,要想共享数据,一般通过中间件来实现。 下面我们尝试用一个全局列表来实现进程间的数据共享: - 8 X3 u1 @" _ `7 U& r& C
( g& V$ ?0 R6 z' b8 Yfrom multiprocessing import Process. w: o* `; n/ J* _% K
3 c; o( E; p: _
- 8 a& B* l( g; f$ C: Z/ O8 Z% W
8 h4 R3 G! X8 Y# g
8 C# w4 Z0 ^. F$ b8 X! }% `' q. @
- 8 ]3 D2 O, C# H& {+ ?- g2 r
. F0 H; t% ^9 j4 Q, \8 _7 g. @lis = []
" E% u$ W/ T1 I9 [7 q, e( ?3 c% f, u k) i
, L# s, z; o" D8 H7 r2 J
1 k! P9 l2 S$ r. M* G. k2 I5 K( C4 C5 g% F; J H
, g2 y, N& Q) L* a
; Q2 O6 d% ^% v% F; c% H5 e3 ~1 y4 O' v* B2 U/ e, k) f5 g! ?5 L
def foo(i):
+ `, O1 w; E- l0 C1 d% j+ d
0 q# ?$ E9 C) q
! P( e2 D- c' ?* |7 w) |" n/ K8 E! r3 j& {
lis.append(i)) z T& J0 v6 k* r, G
" d1 O+ v- {9 x
/ t# ^) Q* e2 v
4 G7 v& H) x9 I! S print("This is Process ", i," and lis is ", lis, " and lis.address is ", id(lis))/ C, x: c& V' x5 f/ j
H. l+ c( ^" x. g2 e- 6 G# |( `7 z+ k
. ?7 z0 N9 x* q- F9 b
+ @) d4 Q6 t5 H
( F" B3 ]; F8 ~2 B$ ?+ D s
. b7 ~5 C) J" r9 V6 @# s' l
3 `0 }& x% _8 K6 ^7 p# O1 Vif __name__ == '__main__':
$ n5 P" c; @; N' K3 V) [) h, W5 \- X, q- q7 q
9 _4 w7 t( s: n" B" x) H4 V( @$ J/ \; \
for i in range(5):* q4 H+ w, M/ q* y+ \' J2 X
! V7 t* y4 z" e8 A. J" x; j+ S
) D6 B9 a0 q% ~- R9 {4 n# ~
4 f7 K- D8 P1 _$ j5 }; r p = Process(target=foo, args=(i,))
3 Q9 U5 y9 ]/ c/ i2 E! E( y" I( Y) C) D9 N, ^
- ! f6 L$ z: x8 p8 ~) |
# b; C& V5 t7 h2 Q
p.start(): C4 m; J" j5 h
6 d' w. r2 T$ M
# w$ ~4 o7 n0 ]
# y0 g3 S/ j* p print("The end of list_1:", lis)( q) a! i' S" o9 M) d% r
( k# ?$ Q( i8 q) P0 U- L" G
2 N- C1 X9 L% l
运行结果:
; n: q' f5 e. M, o" S4 c" }7 \4 e' u/ i" f" J9 R* l( m; I
The end of list_1: []+ B, q: S% [8 K: }% e
; t: N* U- R) a1 q, s8 h2 z- / y& z5 s' J% }/ L! }; R
0 ^9 `/ O; ]. s) m/ B9 J
This is Process 2 and lis is [2] and lis.address is 40356744/ d, w" ` j$ D( F6 F+ e% Q, R
: ?2 u9 J1 J/ T; ^. y
& Y0 d3 J+ H A8 p* {
# ~' p% u5 w/ A3 W _/ ~ L0 eThis is Process 1 and lis is [1] and lis.address is 40291208
+ J0 \: k8 r+ }1 c/ E) D: Y) q' V2 ^# ?# `: M% a$ N
5 S/ f5 n r& `. D) k6 V7 X% P& u. |' p+ L- A# Z
This is Process 0 and lis is [0] and lis.address is 40291208# b7 ~& `3 Q) \: m: M& ?' z4 F
0 F' D. l- x9 [ a; Q# L. W
- 1 g& ^- R$ }0 r" w3 Y9 ^
* X9 P6 a( H2 r$ a- G# d9 X# h+ aThis is Process 3 and lis is [3] and lis.address is 40225672% `8 P" O- E* u( y* e7 r
3 U( v K$ C6 H/ R$ \) ]
* |$ e. U9 l1 }9 A, n) u8 [) M
This is Process 4 and lis is [4] and lis.address is 402912085 R) u6 r: c$ N# m
6 @7 a9 I& A2 V0 X
9 i* z) Z6 ^# \7 S
可以看到,全局列表lis没有起到任何作用,在主进程和子进程中,lis指向内存中不同的列表。 想要在进程之间进行数据共享可以使用Queues、Array和Manager这三个multiprocess模块提供的类。 1.1 使用Array共享数据对于Array数组类,括号内的“i”表示它内部的元素全部是int类型,而不是指字符“i”,数组内的元素可以预先指定,也可以只指定数组的长度。Array类在实例化的时候必须指定数组的数据类型和数组的大小,类似temp = Array('i', 5)。对于数据类型有下面的对应关系:
! [8 k& E5 y+ r1 |- H8 x; s: N+ o! n
$ x. p% K1 d0 n7 T'c': ctypes.c_char, 'u': ctypes.c_wchar,
. g% v) @. P- q$ {" h! ]/ [ m3 V+ B0 C+ R$ X7 U
0 C* @3 l' g& |5 F) E" P v( f6 h4 O
'b': ctypes.c_byte, 'B': ctypes.c_ubyte,
9 z8 }) z& ~/ A; f, v$ s3 S5 }! o) z" \* U5 ^# y
; O5 Z* u2 ^2 C' p' j8 h) r/ @9 D& p& t! _0 v+ q: s! D- B5 v
'h': ctypes.c_short, 'H': ctypes.c_ushort,6 T X& E" P$ s2 C
& T. {" ?" d7 g) p+ M0 E0 L# G
0 j1 I' A: j* ]7 K( Z
$ d0 L1 W" z% `2 z# I. n! W'i': ctypes.c_int, 'I': ctypes.c_uint,
% b- t/ g/ p0 v$ T8 O7 C3 x6 `- V% z7 v+ a) T- G% U- t
8 o8 Q( [1 q( p) K
4 p& I( C* G. v1 N$ R'l': ctypes.c_long, 'L': ctypes.c_ulong,
6 \$ g8 m- [: y1 U: r- a4 E$ R q7 S3 k5 o% j
9 ?; D9 D- a* {, M3 O
! w- Y3 F, C' g4 P3 s'f': ctypes.c_float, 'd': ctypes.c_double
& l/ }( n8 i9 A; h7 _8 t. R" k9 W
4 ~) V8 r- g0 t' h3 |8 z
看下面的例子: - & j: m2 F6 g4 i) @ b
! \5 t* a- K0 m; sfrom multiprocessing import Process
" E* ~' K% ?- N) K( o/ X( W
- z1 i* F$ d% b& s$ A - , Z+ I t; G8 X T8 Z# [! a/ {
7 r) ~9 ~, {, G! R1 w* I% C Ofrom multiprocessing import Array
6 C3 e2 s J# E! h0 @1 h! l ]5 W' j% L; {
5 N* E" n- Y+ B1 [. s9 f) J" \5 X6 x7 }& \2 k
( v4 E. c5 @* d* T0 h! j( R: R" t
; o' m, N" P; Z0 w. H
) W6 _ B3 H& {0 k/ R: b. Q
6 A! o1 z6 h7 {. l5 N" bdef func(i,temp):
, I; k: B. L5 }6 j4 ^) o& s. D0 i5 E6 L' y
2 q* H+ z5 |; [ e% a5 K( u) M" k: i& f
temp[0] += 1005 e, M4 R$ G% ~2 Y2 X: w- P: W
. b5 Z0 w/ j9 L" P+ h) x- : I A+ O; p, p, x
9 T! C" \, X, g" U0 ]: F; V
print("进程%s " % i, ' 修改数组第一个元素后----->', temp[0])
: D5 p! u7 {5 H5 I" a) T- S
4 a8 h: D; P0 t9 H% T( ^+ I4 O
4 |- `" c3 d: o9 r- Y* o3 K$ e
" q% \; P! A# {4 A1 v* ^* r, V9 M+ w+ }5 g
6 X+ ^; s# S' i* ~! L
. A; E6 i7 x% o* \0 H3 Z8 K) f% d/ z
2 D+ K4 |0 c9 v; k* n5 a" j& e9 jif __name__ == '__main__':& k, n# P9 Y \, D. h
+ Y6 R2 B2 p, p% m* m+ M) u
/ @8 C9 K* `. |! `
/ m4 ?- t9 f9 K2 U4 w, B! B" T! ^ temp = Array('i', [1, 2, 3, 4])
' A( k+ p: o4 ^7 J) M8 W
- R6 I: e! D. f6 f0 W6 c, M
4 Z* m0 {. S) t/ a% N1 u- ~3 l1 `
for i in range(10):/ a' e6 U% @% U- |* e- W3 h( ~
% U) c) ?4 J" T2 O$ Z7 W; C1 m8 E
- # ?: W7 U2 o% e2 P& K" p
% G }7 d$ l1 j* D+ Y# R' w& N, d p = Process(target=func, args=(i, temp))
# M; u* d$ D, A/ F4 |- f: X0 z* d: m0 a% M
- , p% G# Q# B. R: l/ Z" J0 T$ p
. Y; y* `$ @4 m- j7 j% [ p.start()4 w; A8 L0 p, ?$ D* j+ S
" }9 P3 i3 G5 v4 @) D9 F5 U7 R8 ^' O n( [& Y4 ^
运行结果:
% s+ Q6 W1 C5 F
2 N9 S; z0 d1 o0 g5 S! D! g进程2 修改数组第一个元素后-----> 1011 u- ^, z* r, w, F! [" C7 C, q( G1 N
/ C3 d/ J( ?$ A$ v" @! u$ A9 z/ [
6 A6 Z5 L8 O6 T4 Z: ?4 x- |3 X$ Y k" \& M; L2 S
进程4 修改数组第一个元素后-----> 201
$ [9 R# m D2 m7 {* n, }& Z
: v( H6 @( P$ R7 U4 v- ' c8 ?" n% A9 r5 w4 j2 ?3 ]% f
8 ]; g: h1 b* ?# I1 Y6 v" {+ b进程5 修改数组第一个元素后-----> 3019 ]; f5 r" I: b' v, f8 [" u
8 c8 N9 A/ r7 D, q1 S/ O - 5 X9 c) r8 G/ {' P1 \
E+ Q, X% N: O" |- y进程3 修改数组第一个元素后-----> 401
1 M3 S& G6 w1 f
* x/ T5 ]: s8 u# |/ x
$ B9 g/ m9 m, p9 P
; d9 {: g( X; {+ R# e% s: s+ k1 |进程1 修改数组第一个元素后-----> 5019 s. O$ \3 ^5 Y- w6 @3 G! H; K
: L" Y; V; K- C0 U
4 v9 C+ A u H9 \7 i4 G( v5 p' A0 Y$ O+ n5 A. y
进程6 修改数组第一个元素后-----> 601
! B. |! W/ H$ k2 O6 |
2 w" L' u% _7 ]8 E( D, B& M3 W- & b+ A7 W7 r& f8 R6 U$ V) ?
Y$ t- {$ s+ |* s进程9 修改数组第一个元素后-----> 701
0 ?+ O/ F1 |6 m3 |5 c# b8 U
9 m* t9 D& R; D) ^8 t8 R% G* V - 6 i$ q$ h$ |( z+ y; @ @6 i5 g
! `, n% o+ S" y进程8 修改数组第一个元素后-----> 801& v5 t5 g$ Q7 w& A0 Q8 r- Q. i
( F7 f2 j. g! Q( y0 H
/ y8 n" R; f! b$ a$ G9 W2 X
% V4 ~) J$ f0 \2 v: p K进程0 修改数组第一个元素后-----> 9013 `+ I6 `- M* r l' h6 s( h
: U) Z8 J# S) x
- " Y% D; b& }; r" x
+ M8 J7 N& K9 s% m
进程7 修改数组第一个元素后-----> 1001; X" F. X$ ?4 q+ O
. V5 G [6 x0 r& Z5 \* r0 W4 |& o. u1 @; ?; X7 f
1.2 使用Manager共享数据通过Manager类也可以实现进程间数据的共享。Manager()返回的manager对象提供一个服务进程,使得其他进程可以通过代理的方式操作Python对象。manager对象支持 list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value ,Array等多种格式。
& e' V6 V! R) G7 f! f' C0 q+ Q; q) k4 \; G- t! f0 P+ M
from multiprocessing import Process. R* e& z7 M3 J M" c1 O+ q* K
6 |! J# L& \% c0 C- 5 S0 h4 v& K% u( t9 q0 a0 ~& i1 S
, r- s4 @6 G& _! f5 ufrom multiprocessing import Manager% E2 w$ j7 o h9 s# M- F
) H3 F1 E, B) [6 m" D - % ~4 L a3 p6 {* B: v& H. j
" |5 s: R7 a [$ E8 H$ d7 z: P4 B" M& K* Q+ r
5 c% K* a3 p; C
- ) g: J( Q' H$ m7 F
}5 U6 d8 _: x
def func(i, dic):
B6 X1 s1 l3 ^; `" k% O
$ A$ C( Z- \" F/ q2 c$ F
K% g: e6 W) I, i& G
& F! C f* @/ M9 i% t3 R" [/ S! Q9 t" {, d dic["num"] = 100+i
' f* u, a- h: |! d
% ]# w4 e4 j# ^! r r- 4 @% W7 U& v; x0 ]& r
0 m% I: p. r/ J: x( Z W print(dic.items())
! h. e$ F8 F9 Q/ J0 L' @
3 x0 x7 ~( K% k; D$ K+ `9 U
% ]* g* N% L3 e! d% t8 _
" G' Z. D7 f' _# A$ l2 [
4 z. q+ R7 ? ^
: z/ }& \" Y: k" d$ H7 I: X
2 Z( h# Y" K6 R$ T% i2 K) G1 x e
) w5 Y @2 |, `" O+ Q$ K7 Y+ y% eif __name__ == '__main__':
, f( J: ]5 }$ m! i* f" w) i5 |1 y# R. D' L4 l5 K) t8 B2 m! v0 N
, H# o! c# w. R# s* t6 }3 ~
: E- D3 V' P0 e# h! G8 \+ y$ ~ e dic = Manager().dict()+ J1 L; R6 @; g; w7 s1 @
+ ?5 @7 j b- y9 ^, }# n# W6 O
- ' z! s2 Z9 i- y- ^6 w- a
* z2 |- a2 A9 u9 I ?" c3 }) \ for i in range(10):
\5 M$ ^5 W# b+ H
1 P3 I( I* e! U" R* q; r% { - L& R n* T; O, Y( v) k
& L+ Q8 u: W3 j) ~+ F7 j/ {! ^% D p = Process(target=func, args=(i, dic))7 t! K! _0 `8 ^) g1 b G
( V) X2 `3 w: r% n! h
+ n& g3 S) f# k2 `
9 L% L* S/ e# p5 H p.start(), a; Z# V. I8 C' u$ S
, L/ ?, h0 a) J2 b# J! r0 D y9 j
& v9 e6 X0 E. K, Z
4 D/ a4 d S7 A+ M. L p.join()
6 \! V! n" S- @* X P
: x; Q$ U( `3 m! N7 |( ^
1 Q" a, f/ J8 r4 q
运行结果: - 1 m! s1 `: \# W7 I2 d
3 \% o: w* v% C% L$ e[('num', 100)]
! A9 m' T$ u& k o6 ?2 I
6 {' Y) ~$ D# R, m1 w6 W E
& O4 E/ \; n- F2 g ^! o- p$ x
, M% a4 |4 e0 @+ x9 _0 n[('num', 101)]
1 D: i! z6 p* U; ^7 H9 Q
% R8 E2 F& A8 t- . [+ w, M# Z7 x1 i7 F
+ e! c4 r$ k) }. `8 T: E( ~* I( l[('num', 102)]
' l/ a4 c' w) \8 @: d8 n6 J
; u% U; L9 b( D$ A
) j4 f$ ~7 F; f( K) W, _! F6 `- G; u$ L8 j
[('num', 103)]! H0 `6 L2 n+ W6 s2 ^
5 J! e5 m' q+ i) J$ d4 s; ]
. m7 m+ b5 s6 [5 v& T& [1 r4 E$ Q& ^% R3 x7 N. t# X
[('num', 104)]! G1 k7 k$ `7 I# {; I6 N& Z, m
4 e0 ^; H8 O, n" f: g F- . l: s4 s& Z4 {/ @* ~
4 Z7 A. x1 K9 a[('num', 105)]# | }' t+ b3 J Y
. V3 T2 r* S5 p3 k
- ; v" Z' q A2 {$ D% X3 S" `
) [ ~0 X! ~0 r* Y
[('num', 106)]
, U$ F# V7 I$ M' x- x* m. a9 M2 A: w* U8 t k
- 9 b% ?2 S" R) T8 D9 f
1 X5 h9 ]' ~% J* k; U[('num', 107)]
- l6 w# g' I V1 X# W' @2 L' \; G0 `# W+ v; [
- " `7 {! @% i' y, A5 k( w3 k
% f' l! x8 W' F2 J. U$ ]
[('num', 108)]
* p0 E; j/ S0 d5 Z' P/ N/ w& j/ u0 Y' H$ e( v7 T
- 9 L: m5 Z: a% H/ `* o7 }/ R
4 @2 Q0 s# b/ s% v2 D" H5 }[('num', 109)] e; k, u& [4 }, v4 d
: n+ ]/ ?% O- @; ^8 Y9 t, p5 |9 W* ]/ V& J* K9 s0 F
1.3 使用queues的Queue类共享数据multiprocessing是一个包,它内部又一个queues模块,提供了一个Queue队列类,可以实现进程间的数据共享,如下例所示: - 0 x/ i1 k3 w' G
8 k2 }# v( N) W( r
import multiprocessing
4 T) a+ L+ C% ]1 W
1 j$ r5 R7 D2 ]
% i$ X2 M- E( ?9 T5 F% A$ g
+ E; A$ d5 D6 ^from multiprocessing import Process
9 ] I) n) z8 s8 _3 J; _9 y) f7 t4 [# G! t! f
- / l! N/ j# {9 Z L+ a
7 p0 ]+ I- ] |6 z, X& K) L( u1 }from multiprocessing import queues. F% X" q S2 m) l2 I% X
, g, ]/ j; L4 m2 T+ p3 R" p
F9 z" b' L8 o v) e; G( h2 j
7 }; S7 ^5 j# \; Q1 V+ G. \) d
I5 m2 z9 m1 R! ^7 D6 H1 B( r3 e) y4 h2 n" _. y0 y
- 1 a' i9 t: h @5 ^9 \
. @% u& a( e2 M/ o
def func(i, q):4 Z E! f8 J; b
! D* F' c! C6 B" E1 d* x
, L. r6 l& q8 r+ U# R& | E( P( C* x. }( \8 X4 Q
ret = q.get()4 s Y0 e) N7 W3 V8 Y0 {0 |
3 q! U6 a/ q( {0 h
- " X8 b8 `8 {/ q
9 h6 b3 O; |; n2 ]* J+ |# q print("进程%s从队列里获取了一个%s,然后又向队列里放入了一个%s" % (i, ret, i))
- A+ _' m1 Y4 E" j1 D, w# E5 h5 L2 U) p( U) S$ c) _ K
0 p0 s( `7 s3 @ U1 r6 A
; I& q5 Q, v' X+ B; \ q.put(i)
, y! P l- q2 s: g8 G) U
/ l7 p- D# Q# r/ j$ N
1 c2 X# } O1 p' C% k
9 E. `# h+ `: n2 S+ z9 t0 g5 d% ]) m
/ L2 A5 Q5 l; V: d4 }9 s( c2 w$ v
" u# \) r. w, {% @8 a" T" m$ a1 w' v' a t0 `! G
if __name__ == "__main__":" i3 f0 H; l# D$ y; e% r! _- o
- I7 q9 Z& n* b* w3 [ w P
- ; R- j4 M5 J: H+ Y7 \, W
# B( H! {9 K7 V9 `% r8 d& N lis = queues.Queue(20, ctx=multiprocessing)
/ v6 @* ]* }7 T+ H n9 D6 @& V) x! x4 l7 p$ L' @# F; E
- # a+ ]; q( B7 S& |% }
: x: Q0 @# ?; h" C( V# H9 d( G3 ] lis.put(0)
2 M; n' b j2 J$ o ~! I; x+ R9 N% F8 _, W
9 H* i3 {5 W. K, F# W+ r- l/ l: D9 l) C6 l5 ]8 V7 P/ v; Z! a' H, O5 w
for i in range(10):
4 M6 e% j8 A% h; P* v" e& f; h. z1 P& N7 Q0 f
7 |/ _ y5 q3 b% P& c1 }/ X( U7 S
1 S, ]; r$ h; | p = Process(target=func, args=(i, lis,))8 d5 t* p# d4 R8 r/ o: R
% {. f) L$ W* p M( ^+ t4 f
- $ }2 r! q- B5 {+ [. o
, l# V: O! J H" s4 o- V8 H
p.start()
6 T. i+ l/ H9 P' y4 |( ?3 E6 u7 V2 L) D- f# ?
$ R% q- q! x O7 ~; z4 c/ t
运行结果: - + D4 Z& H/ E/ O% p- ?
% ^. }+ J2 Y9 f+ U& X5 q9 q9 q
进程1从队列里获取了一个0,然后又向队列里放入了一个1
/ I; N* D) t$ Q' T. r% i1 o" x0 e3 U% N% P. ?
- ; s$ {1 l- u2 ?4 N
$ N! Q1 P) N2 r/ [: y
进程4从队列里获取了一个1,然后又向队列里放入了一个4
3 @! F; G/ _1 b' R ]- F0 m! U, g# F1 j- {7 y) J* x$ R+ C
- " Q; N+ m$ [- j- z0 ^8 e
+ L( q1 v& d. A( v" x
进程2从队列里获取了一个4,然后又向队列里放入了一个2
- a V# S8 ?8 }$ u$ k
4 S F* ~! |: K. ]0 O0 y- u
- R2 M9 S0 N. e4 A/ E, o8 Y8 \/ |! z! J: [- b
进程6从队列里获取了一个2,然后又向队列里放入了一个6
/ F2 V6 _4 Y2 j8 ~7 i0 W7 j- G* @0 Y% c1 u, E# t R
- 5 x3 q9 W- z( V- q
e8 D* {# N6 _' w' J3 Y5 ~- U
进程0从队列里获取了一个6,然后又向队列里放入了一个00 a% C" r8 Q5 P% ~+ b4 }$ O
5 p/ u; i4 o, k9 r# F* E2 h ?
- h: V3 ~; }/ m7 l/ @7 I
7 Q% s- _# j- N; P进程5从队列里获取了一个0,然后又向队列里放入了一个5
9 `7 |$ H3 [8 H1 G/ u, _3 Y
. i0 c; `" |) }( s1 t# Q( H) S6 w - ' g$ v& u. H x9 y0 F4 a, Y! O; b
# H4 ?1 d" s! s" P: r4 V4 N1 v# ~进程9从队列里获取了一个5,然后又向队列里放入了一个9
9 {# W; L/ ?3 C2 ]
1 ?; q5 C' j' d- F2 R
g8 \& D& {4 E1 ]/ r# @0 u5 p# ?6 }2 v' X6 N$ @& T; L
进程7从队列里获取了一个9,然后又向队列里放入了一个71 e) O9 _2 r, Z. H+ b
% a5 I# J* x# f- , Q. z( G) `+ H( `
4 I. E0 k/ S `" n7 O# G" o
进程3从队列里获取了一个7,然后又向队列里放入了一个3
3 X4 T& ^# h9 t, p% N
% a2 @$ }8 V# e m
9 H- r; T1 [/ O" K5 t! w- K8 D2 t3 S2 K6 |0 F( ^0 A) H7 Z
进程8从队列里获取了一个3,然后又向队列里放入了一个8
+ J" O( W- f( k. W" e# y' e- g7 x+ [6 V! l7 f/ h; Y4 `6 d
: d1 ~7 A2 S3 M8 Y- u2 @( g
关于queue和Queue,在Python库中非常频繁的出现,很容易就搞混淆了。甚至是multiprocessing自己还有一个Queue类(大写的Q),一样能实现queues.Queue的功能,导入方式是from multiprocessing import Queue。 2. 进程锁为了防止和多线程一样的出现数据抢夺和脏数据的问题,同样需要设置进程锁。与threading类似,在multiprocessing里也有同名的锁类RLock,Lock,Event,Condition和 Semaphore,连用法都是一样样的,这一点非常友好!
; }* p6 G/ |9 h: k& e
/ J5 {' x% Q' {1 d U+ ofrom multiprocessing import Process1 I- X; v' f# Z
2 _. v8 e/ y* X- T \- * Q6 q S `; }( ?' p2 }: l$ {
9 K6 N- D2 L4 S9 f% zfrom multiprocessing import Array
9 H& b6 K7 m5 y( v6 b# |( w3 T. B$ \& \
- S0 a1 P$ ?& c) s g8 ~( I
6 a; @$ A4 U) D; e+ l. w% |7 L6 j( ?from multiprocessing import RLock, Lock, Event, Condition, Semaphore
7 S3 [4 ~/ w/ C& I& e ~9 d
6 L" N" K, ?3 I$ h% I8 {4 j - $ r+ z8 U! J; e) R
8 y9 h7 n& G- k& r0 ~( Y
import time. ]- Y4 e' g) q3 G
- l3 k; X# x% y$ i/ {, w
8 Q0 S6 e( k& q" l4 y+ D0 `
4 e7 F" @3 f$ z" K; k. O9 V
8 Y8 h, a2 P+ Z; m3 f
8 s( Y3 _ l" T: \9 v
3 M3 r/ C5 z3 V# \8 w j! b# k1 J( [1 m) A3 b
def func(i,lis,lc):8 Z# s3 H" @+ ~* [% {! N5 k, s
( @7 {4 a- c! N( Q& c, i
2 E8 a1 v" ?- s. T0 a" O" ]. h, N5 N; k( K7 o; z9 J) B! w* G3 v
lc.acquire()/ d% K; s( w5 r+ l6 y- G
- J! o6 P0 A& J2 x% S! r6 }7 S# L- , O/ C2 ]5 j! Q9 U5 c
# m+ ]% M0 ^6 T% ?! J3 C lis[0] = lis[0] - 1& Z; T( k! z6 S
( y0 }3 K4 y# E. r; T
8 z; \' M; ]) n
4 D# Q! X7 S2 c, E time.sleep(1)
/ C: Y* b4 x2 w. _$ l- D
" o% E( v9 ?. |, N- % w( m9 X7 U, T; M
, a9 ~7 v1 S1 {; M% t# T
print('say hi', lis[0]) [( Z& c f& }) Y8 P" u/ k
; g3 R7 D, I0 Q- X; L y
1 ?% F# `7 l; V$ s: r: x, ~' D# t' ?! ?! V6 |' p
lc.release()) o/ g/ D# D: s* p( E: Z
$ E. g! ~' A3 K* j8 s9 B4 X
7 e, w8 X/ c! S, A: Q8 D$ \1 j7 O' h3 X8 k& B
2 Y' l7 b2 W. [+ k) r( N
. G( `8 w ~( Q- c
7 y# [2 U) g+ ]! G2 n
% i) j$ }! o' aif __name__ == "__main__":1 [0 D; H- D) {1 t
" @) [8 F/ u: d- i) [% V( U! i9 j
) {1 ]; l8 A! v5 W6 h
$ h! D7 a. @: h! E1 e3 n5 `7 j& W array = Array('i', 1)+ R+ o! n+ E# f. P$ S
; Z0 s8 }4 B8 k, `- K7 y* Q5 B
- - Y# a4 @% t; g6 w
7 T0 D2 R$ o$ v6 p3 v0 o) N
array[0] = 10
4 N6 |/ D$ B( p% }, Z5 o8 k1 v- x7 `4 n- O" d( j
- $ ~) _4 v* d9 H
8 i) _" C" E- w7 d6 r: v% m
lock = RLock()
! M! x6 f: p! y) ]0 e. { o' V3 m$ y. A, d( H# ?9 Y ~
- 1 h: \# c/ K6 v$ @7 O! Y# m) x+ I+ g
5 l7 K. I% q6 R" {9 O0 M for i in range(10):
; o6 n% ]0 D: P& Y5 S$ v
$ G# c. F! r! ?7 A: t$ \6 X N - 4 c& z2 |8 F \' f1 _
. |. ` A; [* i- r! ] p = Process(target=func, args=(i, array, lock))
- s- `9 j0 N/ O, i
( L c, M ]4 m' k0 s3 b - % [8 x7 J7 `; R+ R' [; a2 Y0 V9 ]
, ^6 F- \: ^7 @ f
p.start()+ E0 _; _" T3 c* \
" T. E! V# @' p# l
$ v9 n; }6 W) C0 j; x/ b' b
运行结果: - & E' }5 O& i: o8 z
2 W; ]8 ^: Z, n3 D2 R% ]" S
say hi 9
: v: w, N9 E: {0 r8 a0 J& ]$ F l1 e
( v0 J8 n7 A% ]/ f0 g, n3 t. ], e
say hi 8' X8 X2 a: w) v# r
+ {8 _) J- \) g4 {/ e" ^- " X1 {" z& b8 O" `& {
1 a m+ v& b1 _7 V1 Q, x" v2 r% Z
say hi 7' ]5 o. L! ]) d3 _
7 c+ L' M/ ?' @ { }5 \/ U
2 D) P" i0 ~; d
# a' T, |: @# g8 A% O# d, J' r. usay hi 6
( J5 [& [( }& z% b4 V: v: @! k `6 c3 M/ k3 }$ q1 k( x
- T5 M( }0 O) _0 N3 \
p# h" p5 K! D8 |# H; u/ ssay hi 5
8 t- F# ^" O5 S7 A- @0 _) V% c K
, D1 j0 l0 L. \( V/ \- # `4 |) f% c/ J
: Q. ? R, S9 l- o' W9 ?say hi 4* d, {; w( h" q5 a7 l
8 ~ o* w6 {! z5 ]- } - ) l3 T6 x' D+ S* G
" y* ]0 {2 U, s8 Dsay hi 3
?3 Y9 Q: [1 b! w9 E7 h* ]+ `% E8 {9 i4 f/ R
, Z W* x6 b4 [! _. b$ {* N' ^9 h. O$ Y/ o
* Y8 ~5 a4 C; N# d5 N, R9 J! v* `5 ?say hi 2
8 N) T X( L# F) U
$ p9 O: L o* @5 Q6 L" H! o) L- % s% \$ m6 i* N. t2 b+ l: q
" _. B+ g! p2 Z1 z' o. ]
say hi 14 T% s3 M7 O: C% t9 @4 {
4 H; @6 F! n9 T - - r( {; m0 e6 `' |6 u: H' n* b
' Z: ^# ?' U! Usay hi 0
2 M' O: M# A5 |( O& v' M: ?1 _' \. o
& `( S0 V! M' @+ C9 ^. I5 H
3. 进程池Pool类进程启动的开销比较大,过多的创建新进程会消耗大量的内存空间。仿照线程池的做法,我们可以使用进程池控制内存开销。 比较幸运的是,Python给我们内置了一个进程池,不需要像线程池那样要自己写,你只需要简单的from multiprocessing import Pool导入就行。进程池内部维护了一个进程序列,需要时就去进程池中拿取一个进程,如果进程池序列中没有可供使用的进程,那么程序就会等待,直到进程池中有可用进程为止。 进程池中常用的方法: - $ S5 j2 y( p7 {0 p" M1 U4 j
5 m6 i/ i. e8 p* X; }) x/ m! ~
from multiprocessing import Pool& e" W* i! r1 G4 t
6 y! i( c/ z/ y) W3 d! Q
. l9 C% V9 _$ F7 y4 ?$ |( t5 |' l
7 C% k* U+ L( Kimport time! f* r) T& o2 |5 C
# d% ?9 p6 d3 {0 X. z- * _5 [- m! u# w6 n* {
' T* w( c! s9 h
! n* n4 Y, ~' ?. w
1 c$ E# J/ y2 u# D6 R. d1 o
- ~' e2 a, V& S, X8 u
! F2 h5 s7 v/ P/ Ndef func(args):" a7 i! C) A' f& r9 @) R
% _" T: p6 o0 V2 E% \
- 4 ^1 w2 q6 o! R: ?
$ j' r, Y+ g+ i8 `. f' H* }9 \ time.sleep(1)/ m- D9 p, I1 b5 Q. l6 A
V( p4 f9 W6 B9 g( F8 e& z
- + E$ ^' k1 i6 K
% ]4 J& H) s2 U$ D& @) c: Z
print("正在执行进程 ", args)
2 K. C- N0 T0 J3 P3 N* b
, ?; ~1 b+ q n* Z - 1 B6 I8 L% {" F5 s
% P- D" M9 ?* l+ q
, N7 W! F/ w( B: q( b
, ]) U! k8 Y5 M! ~
- $ n6 O4 E7 p Z. Z8 U5 y; i' i8 }( W4 U
+ m( `! d+ O9 c! `9 ~* a) [ c
if __name__ == '__main__':8 a( u( y' a3 ~; V. `
7 _6 u& {4 Q# S3 f$ U+ \+ W8 R) r
- o& {3 Z9 r; l" }& E5 M
" j% C' p. R( e: C; A' w+ U# l
4 \& Z7 c s: N# @1 n$ D1 n/ q4 i: l% [
- ) X! w1 q" R9 T; ?) k' R
) L7 w+ r9 r. z
p = Pool(5) # 创建一个包含5个进程的进程池( m' f0 ^: _; X/ b/ [
. h, y" h: z% O# r
- 3 h- C9 X5 Z; X0 e2 ~
. Y5 S% c( y$ [( n. F% F0 F0 P+ ]" ]- v# d y
8 R3 @4 p V! Y' x7 Y% F
# l$ I1 h9 T6 A/ i" K
3 l% o2 i S$ t( O& m6 a for i in range(30):
# `. U$ c/ a" d, u4 d
: K- b3 _ a2 d2 U/ j- / h$ ~: Y0 F6 G2 T* P
8 ?6 o. N$ B* H% ^ p.apply_async(func=func, args=(i,))
7 X5 G2 Y+ b$ y1 v' S4 z; S- V9 J
- 7 O) j. \* E- b& @" x) v5 k2 _
) X; L( I. K, P; Z9 q& @ m* e- J. u- a2 o+ \1 }! Q
& m) `6 c" @! y0 a1 h
. s- w: {- C( f, b- j. Q# l
3 T# c2 d( t4 v% J! }7 C% f. x9 r p.close() # 等子进程执行完毕后关闭进程池6 b" y$ U" ~. @$ j
4 V5 P: ?- Q$ w0 v& U
- , I" [4 B i0 [
6 F$ e2 ?$ @- M+ m
# time.sleep(2)$ t/ _/ h* ~" E" a1 H
* {8 Q/ n" @0 [5 b8 Q8 y
6 t- v+ U. a. B9 i- y0 l8 H# `- k) h4 W" ]8 f; ~9 F6 D$ p9 }
# p.terminate() # 立刻关闭进程池
, D6 p$ h* Y ~; `: @2 I. t2 ?0 J, g/ _6 [6 l* c6 Z& e
- 5 @/ ]; \/ R: ?- J) N9 G
% @- |& U3 J- m1 T- H9 u, A8 L8 e
p.join()" ?( X& h$ B) O+ J4 z$ [" f
4 Z: C& Z+ r3 B/ Q% }0 f
; e m% v8 {- Z; `1 @7 c8 {9 Y( \
( L/ n- |" G& c. L, K% j/ [, W请继续关注我 4 A) ^" W0 ?2 s
) U( G3 l- s( z- d/ _6 @+ v& d
|