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