zoukankan      html  css  js  c++  java
  • 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)。对于说英语的人,纸张上打印的或屏幕上显示的英文单词都算作明文。

     

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

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

     

  • 相关阅读:
    mysql事务隔离级别回顾
    单链表倒数第K个节点的查找和显示
    mysql 行转列,对列的分组求和,对行求和
    获取分组后统计数量最多的纪录;limit用法;sql执行顺序
    You can't specify target table 'e' for update in FROM clause
    mysql 行转列 (结果集以坐标显示)
    springmvc执行流程 源码分析
    jdk动态代理 案例
    项目日志log管理
    apache和tomcat的区别
  • 原文地址:https://www.cnblogs.com/jinzejun/p/9128782.html
Copyright © 2011-2022 走看看