• Python共享内存

共享内存有两个结构,一个是 Value, 一个是 Array,这两个结构内部都实现了锁机制,因此是多进程安全的。

Value 和 Array 都需要设置其中存放值的类型,d 是 double 类型,i 是 int 类型,具体的对应关系在Python 标准库的 sharedctypes 模块中查看。

 

 

  • 习题1
1 from multiprocessing import Value, Array, Process
 2 
 3 def woker(arr):
 4     for i in range(len(arr)):
 5         arr[i] = -arr[i]
 6 
 7 if __name__ == '__main__':
 8     arr = Array('i', [x for x in range(10)])
 9     print(arr)
10     print(arr[:])
11     p = Process(target=woker, args=(arr,))
12     p.start()
13     p.join()            # 等子进程先执行完,否则两次print结果相同
14     print(arr[:])
<SynchronizedArray wrapper for <multiprocessing.sharedctypes.c_int_Array_10 object at 0x102c76510>>
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

 

 

  • Manager -- 专门用来做数据共享的模块

上面的共享内存支持两种结构 Value 和 Array。 Python 中还有一个强大的Manager,专门用来做数据共享。

其支持的类型非常多,比如list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Queue, Value 和 Array。

一个 Manager 对象是一个服务进程,推荐多进程程序中,数据共享就用一个 manager 管理。

 

 

  • 习题2
1 from multiprocessing import Manager, Process
 2 
 3 def worker(dt, lt):
 4     for i in range(10):
 5         dt[i] = i*i
 6     lt += [x for x in range(11, 20)]
 7 
 8 if __name__ == '__main__':
 9     manager = Manager()
10     dt = manager.dict()
11     lt = manager.list()
12     p = Process(target=worker, args=(dt, lt))
13     p.start()
14     p.join(timeout=3)
15     print(type(dt))
16     print(dt)
17     print(type(lt))
18     print(lt)
<class 'multiprocessing.managers.DictProxy'>
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
<class 'multiprocessing.managers.ListProxy'>
[11, 12, 13, 14, 15, 16, 17, 18, 19]

 

 

  • pool -- 进程管理

如果有50个任务要执行, 但是 CPU 只有4核, 你可以创建50个进程来做这个事情。但是大可不必,徒增管理开销。如果你只想创建4个进程,让他们轮流替你完成任务,不用自己去管理具体的进程的创建销毁,那 Pool 是非常有用的。

Pool 是进程池,进程池能够管理一定的进程,当有空闲进程时,则利用空闲进程完成任务,直到所有任务完成为止。

Pool 进程池创建4个进程,不管有没有任务,都一直在进程池中等候,等到有数据的时候就开始执行。
Pool 的 API 列表如下:

  • apply(func[, args[, kwds]])
  • apply_async(func[, args[, kwds[, callback]]])
  • close()
  • terminate()
  • join()

注意:在调用pool.join()之前,必须先调用pool.close(),否则会出错。执行完close()后不会有新的进程加入到pool中,join()会等待所有子进程结束。

pool.apply_async  非阻塞(异步执行),定义的进程池最大进程数可同时执行

pool.apply      阻塞,一个进程结束后释放回池,下一个进程才开始执行

 

 

  • 习题3
1 import multiprocessing
 2 import time
 3 
 4 
 5 def fun(msg):
 6     print("#########start#### {0}".format(msg))
 7     time.sleep(3)
 8     print("#########end###### {0}".format(msg))
 9 
10 
11 if __name__ == '__main__':
12     print("start main")
13     pool = multiprocessing.Pool(processes=3)
14     for i in range(1, 7):
15         msg = "hello {0}".format(i)
16         # pool.apply_async(fun, (msg,))# 执行时间 6s+
17         pool.apply(fun, (msg,))   #执行时间 6*3=18+
18     pool.close()#在调用join之前,要先调用close,否则会报错,close执行完不会有新的进程加入到pool
19     pool.join()#join 是等待所有的子进程结束
20     print("end main")
start main
#########start#### hello 1
#########end###### hello 1
#########start#### hello 2
#########end###### hello 2
#########start#### hello 3
#########end###### hello 3
#########start#### hello 4
#########end###### hello 4
#########start#### hello 5
#########end###### hello 5
#########start#### hello 6
#########end###### hello 6
end main

 

1 import multiprocessing
 2 import time
 3 
 4 
 5 def fun(msg):
 6     print("#########start#### {0}".format(msg))
 7     time.sleep(3)
 8     print("#########end###### {0}".format(msg))
 9 
10 
11 if __name__ == '__main__':
12     print("start main")
13     pool = multiprocessing.Pool(processes=3)
14     for i in range(1, 7):
15         msg = "hello {0}".format(i)
16         pool.apply_async(fun, (msg,))# 执行时间 6s+
17         # pool.apply(fun, (msg,))   #执行时间 6*3=18+
18     pool.close()#在调用join之前,要先调用close,否则会报错,close执行完不会有新的进程加入到pool
19     pool.join()#join 是等待所有的子进程结束
20     print("end main")
start main
#########start#### hello 1
#########start#### hello 2
#########start#### hello 3
#########end###### hello 1
#########end###### hello 2
#########end###### hello 3
#########start#### hello 4
#########start#### hello 5
#########start#### hello 6
#########end###### hello 5
#########end###### hello 6
#########end###### hello 4
end main

 

 

  • threading -- 多线程,IO密集型操作

多线程实现方式有两种:

  方法一:将要执行的方法作为参数传给Thread的构造方法(和多进程类似)

      t = threading.Thread(target=func, args=(i,))

  方法二:从Thread()继承,并重写run()

 

线程 < 进程,1个父进程中含多个线程。

多线程和多进程的不同之处在于:多线程本身是可以和父进程共享内存的。这也是为什么其中一个线程挂掉会导致其他线程也死掉的道理。

 

 

  • 习题4
1 import threading
 2 import time
 3 
 4 def worker(args):
 5     print("开始子进程 {0}".format(args))
 6     time.sleep(args)
 7     print("结束子进程 {0}".format(args))
 8 
 9 if __name__ == '__main__':
10 
11     print("start main")
12     t1 = threading.Thread(target=worker, args=(1,))
13     t2 = threading.Thread(target=worker, args=(2,))
14     t1.start()
15     t2.start()
16     t1.join()
17     t2.join()
18     print("end main")
start main
开始子进程 1
开始子进程 2
结束子进程 1
结束子进程 2
end main

 

 

  • 习题5
1 import threading
 2 import time
 3 
 4 class Hello(threading.Thread):
 5     def __init__(self, args):
 6         super(Hello, self).__init__()
 7         self.args = args
 8 
 9     def run(self):
10         print("开始子进程 {0}".format(self.args))
11         time.sleep(1)
12         print("结束子进程 {0}".format(self.args))
13 
14 if __name__ == '__main__':
15 
16     a = 1
17     print("start main")
18     t1 = Hello(1)
19     t2 = Hello(2)
20     t1.start()
21     t2.start()
22     print("end main")
start main
开始子进程 1
开始子进程 2
end main
结束子进程 1
结束子进程 2

 

 

  • 习题6
1 import threading
 2 import time
 3 
 4 class Hello(threading.Thread):
 5     def __init__(self, args):
 6         super(Hello, self).__init__()
 7         self.args = args
 8         global a
 9         print("a = {0}".format(a))
10         a += 1
11 
12     def run(self):
13         print("开始子进程 {0}".format(self.args))
14         print("结束子进程 {0}".format(self.args))
15 
16 if __name__ == '__main__':
17     a = 1
18     print("start main")
19     t1 = Hello(5)
20     time.sleep(3)
21     t2 = Hello(5)
22     t1.start()
23     t2.start()
24     print("#####a = {0}####".format(a))
25     print("end main")
start main
a = 1
a = 2
开始子进程 5
结束子进程 5
开始子进程 5
结束子进程 5
#####a = 3####
end main

 

 

  • 习题7 (线程池)
1 import threadpool
 2 
 3 def hello(m, n, o):
 4     print("m = {0}  n={1}  o={2}".format(m, n, o))
 5 
 6 if __name__ == '__main__':
 7     # 方法1
 8     lst_vars_1 = ['1', '2', '3']
 9     lst_vars_2 = ['4', '5', '6']
10     func_var = [(lst_vars_1, None), (lst_vars_2, None)]
11     # 方法2
12     # dict_vars_1 = {'m': '1', 'n': '2', 'o': '3'}
13     # dict_vars_2 = {'m': '4', 'n': '5', 'o': '6'}
14     # func_var = [(None, dict_vars_1), (None, dict_vars_2)]
15 
16     pool = threadpool.ThreadPool(2)
17     requests = threadpool.makeRequests(hello, func_var)
18     [pool.putRequest(req) for req in requests]
19     pool.wait()
m = 1  n=2  o=3
m = 4  n=5  o=6