zoukankan      html  css  js  c++  java
  • python中并发编程基础1

    并发编程基础概念

    1.进程。
    1. 什么是进程?

      正在运行的程序就是进程。程序只是代码。

    2. 什么是多道?

      多道技术:

      1.空间上的复用(内存)。将内存分为几个部分,每个部分放入一个程序,这样同一时间在内存中就有了多道程序。

      2.时间上的复用(CPU的分配)。只有一个CPU,如果程序在运行过程中遇到了I/O阻塞或者运行时间足够长。操作系统会按照算法将CPU分配给其他程序使用,依次类推。直到第一个程序被重新分配到CPU会继续运行。

      多道技术中的问题解决:

      空间复用:程序之间的内存必须分割。这种分割需要在硬件层面实现,由操作系统控制。保证安全性和稳定性。

    3. multiprocessing模块的使用

      python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源,python中大部分情况需要使用多进程。python提供了multiprocessing模块。

      multiprocessing模块是用来开启子进程,并可以在子进程中定制任务。

    4. Process类

      process类的作用是用来创建进程的类。

      Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)
      强调:

      1. 需要使用关键字的方式来指定参数

      2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号

      参数介绍:

      1、group参数未使用,值始终为None

      2、target表示调用对象,即子进程要执行的任务

      3、args表示调用对象的位置参数元组,args=(1,2,'ming',)

      4、kwargs表示调用对象的字典,kwargs={'name':'ming','age':20}

      5、name为子进程的名称

     

      **方法介绍**:

    1、p.start():启动进程,并调用该子进程中的p.run()

    2、p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法  

    3、p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁

    4、p.is_alive():如果p仍然运行,返回True

    5、p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程

     

      **属性介绍:**

    1、p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置

    2、p.name:进程的名称

    3、p.pid:进程的pid

    4、p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
    5、p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)

     

       5.Process类的使用

      
    #创建进程的第一种方式
       ##注意:在windows 中,开启一个子进程就是完全复制一个父进程的代码并运行。如果不写在if __name__ == '__main__':下面会形成一个无穷的循环。if __name__ == '__main__':的作用是以当前文件运行__name__ 会== '__main__'
       
       from multiprocessing import Process
       import os
       def task():
           print('task  run')
           print('子进程task', os.getpid())
           print('子进程task父进程', os.getppid())
           
       
       if __name__ == '__main__':
           #创建子进程p = Process
           p = Process(target=task, name= '这是子进程')
           p.start()  # 给操作系统发送通知 要求操作系统开启进程,会自动调用run()方法
           print('py文件进程', os.getpid())
           print('py文件进程的父进程', os.getppid())
           
       ###输出结果
       py文件进程 10532
       py文件进程的父进程 15348   
       task  run
       子进程task 4356
       子进程task父进程 10532
      
    #开启进程的第二种方式
       #创建一个类,该类继承Process类,覆盖Process中的run方法,其优势是 可以自定义 进程的属性和行为 来完成一些额外任务 例如下载
       from multiprocessing import Process
       import os
       class MyProcess(Process):
           def __init__(self, url):
               self.url = url
               super().__init__()
           def run(self):  #方法名必须是run
               print('下载文件。。。。', self.url)
               print('子进程run的进程ID', os.getpid())
               print('子进程run的父进程ID', os.getppid())
       if __name__ == '__main__':
           p = MyProcess('21215135')  
           p.start()   #会自动执行run
           print('py文件的进程ID', os.getpid())
           print('py文件的父进程ID', os.getppid())
          
    1. 进程之间的内存空间是隔离的

      from multiprocessing import Process
      import time
      ​
      a = 1002020212def test():
          global a
          a = 33520
          print('test进程的a', a)
      ​
      if __name__ == '__main__':
          p = Process(target=test)   #创建进程
          p.start()           #启动进程
      ​
          time.sleep(1)
          print('py文件进程中的a', a)
          
      ###输出结果
      test进程的a 33520
      py文件进程中的a 1002020212
      结论:
      1.子进程中的数据修改,不会影响父进程。
      2.子进程的创建和父进程无关。
    2. Process对象的join方法

      join方法的作用是:父进程等待子进程结束。

      from multiprocessing import Process
      import time
      ​
      def task(num):
          # time.sleep(2)
          print('我是%s号进程' % num)
      ​
      if __name__ == '__main__':
          start_time = time.time()
          ps = []
          for i in range(5):
              s = Process(target=task, args=(i,))
              s.start()
              ps.append(s)
          for n in ps:
              n.join(0.04)
          print(time.time()-start_time)
          print('over')
    3. Process对象常用属性

      from multiprocessing import Process
      import time
      ​
      def test():
          time.sleep(3)
          print('life is so short, i use python')
      ​
      if __name__ == '__main__':
          p = Process(target=test, name='daidai')
          p.start()
          print(p.name)  #进程名
          print(p.is_alive())   #进程是否存活
          # p.terminate()       #终止进程
          print(p.pid)  
          
          ###
          daidai
          True
          20108
          life is so short, i use python
    4. 孤儿进程和僵尸进程

      孤儿进程:是指父进程已经终止,但是自己还在运行

          孤儿进程是无害的:例如QQ打开了浏览器, 然后QQ关闭,浏览器运行

      僵尸进程:是指子进程完全执行完所有的任务,已经终止了但是还残留一些信息。(进程id 和 进程名等)

          但是父进程没有处理这些残留信息,导致残留信息占用系统内存。

      当出现大量的僵尸进程时,会占用系统资源,可以将他的父进程杀掉,僵尸成了孤儿,然后操作系统会负责收回内存。

    5. 基于多进程的TCP套接字通信

        

    ##基于多进程实现并发通信服务器
    
    from socket import *
    from multiprocessing import Process
    import struct
    
    server = socket()
    server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    server.bind(('127.0.0.1', 33520))
    server.listen()
    def communicate(c, addr):
        try:
            while True:
                data = c.recv(4)   #1
                msg_len = struct.unpack('i', data)[0]
                msg_data = c.recv(msg_len)  #2
                if not msg_data:
                    err_info = '对方正在输入!'
                    err_info_data = err_info.encode('utf-8')
                    back_len_data = struct.pack('i', len(err_info_data))
                    c.send(back_len_data)
                    c.send(err_info_data)
                back_len = struct.pack('i', len(msg_data))
                c.send(back_len)
                c.send(msg_data)
                print(msg_data.decode('utf-8'))
        except Exception as e:
            print(e)
    
    
    
    if __name__ == '__main__':
        while True:
            c, addr = server.accept()
            p = Process(target=communicate, name=None, args=(c, addr))
            p.start()
            
            
    
            
    #客户端,可开启多个,但是每连接一个就开启一个进程
    from socket import *
    import struct
    
    client = socket()
    client.connect(('127.0.0.1', 33520))
    while True:
        msg = input('请输入发送的消息:').strip()
        msg_data = msg.encode('utf-8')
        msg_len_s = struct.pack('i', len(msg_data))
        client.send(msg_len_s)
        client.send(msg_data)
        data_len = client.recv(4)  #收到消息长度
        length = struct.unpack('i', data_len)[0]
        data = client.recv(length)
        back_msg = data.decode('utf-8')
        print('返回的消息:%s' % back_msg)
  • 相关阅读:
    控制C++的类只能在堆分配或只能在栈分配
    static 相关随笔
    虚拟继承
    虚函数和纯虚函数有以下所示方面的区别(转)
    构造函数 析构函数
    标准C++中有没有接口和纯抽象类的概念?(转)
    抽象类和接口(转)
    如何快速正确的安装 Ruby, Rails 运行环境
    NSRunLoop
    UIImagePickerController之死因 .
  • 原文地址:https://www.cnblogs.com/5j421/p/10192293.html
Copyright © 2011-2022 走看看