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