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