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