Python 3学习 ——Python 多进程、协程、编码

Python 学习——Python 多进程、协程、编码

 写此博客 是为了激励自己,并且将自己的心得以及遇到的问题与人分享

一、进程

  1.概述

  multiprocessing 包是 Python 中的多进程管理包。与 thread.Threading 类似,可以利用 multiprocessing 对象来创建一个进程。该 Processing 对象与 Thread 对象的用法相同,也有 start() run() join() 的方法。具体使用看下面代码实现。使用这些 API 的时候有如下几点注意事项:  

  •   十分有必要对每个 Process 对象调用 join() 方法,阻止进程成为僵尸进程的一个手段。在多线程中由于只有一个进程,所以不需要采用这种手段。
  •   两个进程之间不能够共享数据,如果想共享数据要有一个第三方来对两者进行沟通共享。优先使用 Pipe 和 Queue ,避免使用 Lock / Event / Semaphone / Condition 等同步方式。  
  •   Windows 系统下,要想启动一个子进程,必须加上 If __name__ == "__main__": ,进程相关的要写在这句下面。
 1 #author:"LFD"
 2 #date: 2018/6/8
 3 from multiprocessing import Process
 4 import time
 5 
 6 def f(name):
 7     time.sleep(1)
 8     print('hello',name,time.ctime())
 9 
10 if __name__ == "__main__":
11     p_list = []
12     for i in range(3):
13         p = Process(target=f,args=('liufeiduo',))    # 创建进程
14         p_list.append(p)
15         p.start()
16     for p in p_list:
17         p.join()
18 
19     print('jincheng end!')
20 
21 ''' # 运行结果:
22 hello liufeiduo Fri Jun  8 11:15:46 2018
23 hello liufeiduo Fri Jun  8 11:15:46 2018
24 hello liufeiduo Fri Jun  8 11:15:46 2018
25 jincheng end!
26 '''
creat jincheng_1

上面是通过方法实现多进程;

下面是通过调用类实现多进程;

 1 from multiprocessing import Process
 2 import time
 3 
 4 class MyProcess(Process):
 5     def __init__(self,name):
 6         super(MyProcess,self).__init__()
 7         self.name = name
 8     def run(self):
 9         time.sleep(1)
10         print('hello',self.name,time.ctime())
11 
12 if __name__ == '__main__':
13     p_list = []
14     for i in range(3):
15         p = MyProcess('liufeiduo')
16         p.start()
17         p_list.append(p)
18 
19     for p in p_list:
20         p.join()
21 
22     print('end')
creat jincheng_2

  2.进程关系 

 1 from multiprocessing import Process
 2 import os,time
 3 
 4 def info(title):
 5     print(title)
 6     print('module name:',__name__)
 7     print('parent process:',os.getppid())
 8     print('process id:',os.getpid())
 9 
10 def f(name):
11     pass
12 
13 if __name__ == '__main__':
14     info('33[32;1mmain process line33[0m')
15     time.sleep(5)
16     p = Process(target=info,args=('bob',))
17     p.start()
18     p.join()
19 
20 
21 
22 ''' 运行结果:
23 main process line
24 module name: __main__
25 parent process: 7708     7708 是Pycharm 在电脑上分得的进程ID
26 process id: 13972
27 bob
28 module name: __mp_main__
29 parent process: 13972
30 process id: 6024
31 
32 '''
jincheng relationship

  3.实现不同进程间的通信

  通过队列实现 ( queue ) :

 1 #author:"LFD"
 2 #date: 2018/6/9
 3 
 4 from multiprocessing import Process,Queue
 5 import time
 6 def f(q):
 7     q.put([42,2,'hello',])
 8     print('main q id:', id(q))
 9 
10 
11 if __name__ == '__main__':
12     q = Queue()
13     p_list = []
14     print('main q id:',id(q))
15 
16     for i in range(3):
17         p = Process(target=f,args=(q,))#args=(q,) 把q当作参数传入到子进程当中 就可以找到了
18         p_list.append(p)
19         p.start()
20 
21     print(q.get())  # 两个进程间数据相互独立 是取不出来的
22     print(q.get())
23     print(q.get())
24     
25 ''' 执行结果:
26 main q id: 1806769092704
27 main q id: 2077092271608
28 [42, 2, 'hello']
29 main q id: 2579859953200
30 [42, 2, 'hello']
31 main q id: 2635574990216
32 [42, 2, 'hello']
33 '''
jincheng talk-Queue

  通过 Pipe 实现:

 1 from multiprocessing import Process,Pipe
 2 
 3 def f(conn):
 4     conn.send('约么')
 5 
 6     print(conn.recv())
 7     conn.close()
 8 
 9 if __name__ == '__main__':
10     parent_conn,child_conn = Pipe()
11     p = Process(target=f,args=(child_conn,))
12     p.start()
13     print(parent_conn.recv())
14 
15     parent_conn.send('')
16     p.join()
17 
18 
19 
20 ''' 运行结果:
21 约么
22 23 '''
jincheng talk-Pipe

   4.数据共享—— Manager

 1 from multiprocessing import Process, Manager
 2 
 3 def f(d, l,n):
 4     d[n] = '1'
 5     d['2'] = 2
 6     d[0.25] = None
 7     l.append(n)
 8     print(l)
 9 
10 if __name__ == '__main__':
11     with Manager() as manager:
12         d = manager.dict()
13 
14         l = manager.list(range(5))
15         p_list = []
16         for i in range(10):
17             p = Process(target=f, args=(d, l,i))
18             p.start()
19             p_list.append(p)
20         for res in p_list:
21             res.join()
22 
23         print(d)
24         print(l)
25         
26         
27 '''     执行结果:
28 [0, 1, 2, 3, 4, 0]
29 [0, 1, 2, 3, 4, 0, 1]
30 [0, 1, 2, 3, 4, 0, 1, 2]
31 [0, 1, 2, 3, 4, 0, 1, 2, 3]
32 [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
33 [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5]
34 [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6]
35 [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7]
36 [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8]
37 [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
38 {0: '1', '2': 2, 0.25: None, 1: '1', 2: '1', 3: '1', 4: '1', 5: '1', 6: '1', 7: '1', 8: '1', 9: '1'}
39 [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
jincheng talk-Manager

 二、协程

  协程,又称微线程,纤程。英文名Coroutine。一句话说明什么是线程:协程是一种用户态的轻量级线程

  优点:

  •   无需线程上下文切换的开销  
  • 无需原子操作锁定及同步的开销方便切换控制流,简化编程模型
  • "原子操作(atomic operation)是不需要synchronized",所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序是不可以被打乱,或者切割掉只执行部分。视作整体是原子性的核心。
  • 高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。

  缺点:

  • 无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
  • 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序

   1.通过 yeild 实现协程代码实例:

 1 #author:"LFD"
 2 #date: 2018/6/11
 3 import time
 4 import queue
 5 
 6 
 7 def consumer(name):
 8     print("--->starting eating baozi...")
 9     while True:
10         new_baozi = yield
11         print("[%s] is eating baozi %s" % (name, new_baozi))
12         # time.sleep(1)
13 
14 
15 def producer():
16     r = con.__next__()
17     r = con2.__next__()
18     n = 0
19     while n < 5:
20         n += 1
21         print("33[32;1m[producer]33[0m is making baozi %s" % n)
22         con.send(n)
23         con2.send(n)
24         
25 
26 
27 if __name__ == '__main__':
28     con = consumer("c1")
29     con2 = consumer("c2")
30     p = producer()

  2.greenlet 是一个用C实现的协程模块,相比与python自带的yield,它可以使你在任意函数之间随意切换,而不需把这个函数先声明为generator 。

 1 from greenlet import greenlet
 2 
 3 
 4 def test1():
 5     print(12)
 6     gr2.switch()# 跳转到 test2 去执行  switch 方法实现切换
 7     print(34)
 8     gr2.switch()# 再次跳转到test2 去执行了
 9 
10 
11 def test2():
12     print(56)
13     gr1.switch()# 跳转回 test1 执行
14     print(78)
15 
16 
17 gr1 = greenlet(test1)
18 gr2 = greenlet(test2)
19 gr1.switch()

  3.Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。

 1 import gevent
 2 
 3 
 4 def func1():
 5     print('33[31;1m李闯在跟海涛搞...33[0m')
 6     gevent.sleep(2)
 7     print('33[31;1m李闯又回去跟继续跟海涛搞...33[0m')
 8 
 9 
10 def func2():
11     print('33[32;1m李闯切换到了跟海龙搞...33[0m')
12     gevent.sleep(1)
13     print('33[32;1m李闯搞完了海涛,回来继续跟海龙搞...33[0m')
14 
15 
16 gevent.joinall([
17     gevent.spawn(func1),
18     gevent.spawn(func2),
19     # gevent.spawn(func3),
20 ])

 

三、Python2 和 Python3 的编码

  编码:基本概念很简单。首先,我们从一段信息即消息说起,消息以人类可以理解、易懂的表示存在。我打算将这种表示称为“明

文”(plain text)。对于说英语的人,纸张上打印的或屏幕上显示的英文单词都算作明文。

 

其次,我们需要能将明文表示的消息转成另外某种表示,我们还需要能将编码文本转回成明文。从明文到编码文本的转换称为“编码”,从编码

文本又转回成明文则为“解码”。

 

原文地址:https://www.cnblogs.com/jinzejun/p/9128782.html