zoukankan      html  css  js  c++  java
  • 并发编程(一)

    并发编程(上)

    操作系统发展史

    操作系统的发展史

    穿孔卡片:

    一个计算机机房,一次只能被一个卡片使用.

    缺点:CPU利用率最低.

    联机批处理系统:

    支持多用户去使用一个计算机机房.

    脱机批处理系统:

    高速磁盘:提高文件的读取速度

    优点:提高CPU的利用率

    进程基础

    进程是对正在运行程序的一个抽象.

    1. 操作系统的作用

      隐藏丑陋复杂的硬件接口,提供良好的抽象接口

      管理,调度进度,并且将多个进程对硬件的竞争变得有序

    2. 多道技术(基于单核情况下研究):

      单道:多个使用使用CPU时是串行.

      多道技术:

      空间上的复用-->一个CPU可以提供给多个用户去使用.

      时间上的复用-->切换 + 保存状态

      IO操作:input();print();time.sleep(3)

      1 若CPU遇到IO操作,会立即将当前执行程序CPU使用权断开

      2 若一个程序使用CPU的时间过长,会立即将当前执行程序CPU使用权断开.

      特点:程序的执行率降低

    进程调度
    1. 先来先服务调度算法

      a,b程序,若A先来,先占用CPU;缺点是程序A先使用,程序B必须等待程序A使用CPU结束后才能使用.

    2. 短作业优先调度算法

      a,b程序,谁的用时短,先优先调度使用CPU;缺点是若程序A使用时间长,有N个程序使用时间短.必须等待所有短的程序结束后才能使用.

    3. 时间片轮转法

      CPU执行的时间一秒钟,加载N个程序,将要一秒等分成N个时间片.

    4. 多级反馈队列

      将执行优先分为多层级别.

      一级;优先级最高

      二级;优先级第二,依次类推

    并发与并行

    ==并行==

    并行是指两者同时执行,比如赛跑,两个人都在不停的往前跑;(资源够用,比如三个线程,四核CPU)

    ==并发==

    并发是指资源有限的情况下,两者交替轮流使用资源,比如一段路(单核CPU资源)同时只能过一个人,A走一段后,让给B,B用完继续给A,交替使用,目的是提高效率.

    同步异步阻塞非阻塞
    1. 同步

      若有两个任务需要提交,在提交第一个任务时,必须等待该任务执行结束后,才能继续提交并执行第二个任务

    2. 异步

      若两个任务需要提交,在提交第一个任务时,不需要原地等待,立即可以提交并执行第二个任务

    3. 阻塞

      阻塞态,遇到IO一定会阻塞(凡是遇到IO操作的进程,都会进入阻塞态.若IO结束,必须重新进入就绪态.

    4. 非阻塞

      就绪态(所有进程创建时都会进入就绪态,准备调度)

      运行态(调度后的进程,进入运行态)

    创建进程的两种方式

    ==UNIX和Windows创建进程==

    1. 在UNIX中该系统调用是:fork,fork会创建一个与父进程一模一样的副本,二者有相同的映像,同样的环境字符串和同样的打开文件(在shell解释器进程中,执行一个命令就会创建一个子进程)
    2. 在Windows中该系统调用是: createprocess, createprocess既处理进程的创建.也负责八正确的程序装入新进程.

    关于创建子进程,UNIX和Windows:

    1. 相同的是: 进程创建后,父进程和子进程有各自不同的地址空间,(多道技术要求物理层面实现进程之间内存的隔离),任何一个进程在其他地址空间中的修改都不会影响到另外一个进程.
    2. 不同的是:在UNIX中,子进程的初始地址空间是父进程的一个副本,提示:子进程和父进程是可以有只读的共享内存区的,但是对于Windows系统来说,从一开始父进程与子进程的地址空间就是不同的.

    进程的结束:1.正常退出;2.出错退出;3.严重错误;4.被其他进程杀死

    开启多进程(multiprocess.process)

    multiprocess模块

    仔细来说,multiprocess不是一个模块,而是python中一个操作,管理进程的包.由于提供的子模块非常的多,为了方便归类记忆,可以分为四个部分:创建进程部分,进程同步部分,进程池部分,进程之间数据共享.

    1. multiprocess.process模块

      process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建.

    2. process模块

      process([group [,target [,name [,args [,kwargs]]]]])

      由上面类实例化得到的对象,表示一个子进程的任务(尚未启动)

      强调:

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

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

      参数介绍:

      1. group参数未使用,值始终为none
      1. target表示调用对象,即子进程要执行的任务
      1. args表示第哦啊用对象的位置参数元组,args=(q,2,'egon').
      2. kwargs表示调用对象的字典,kwargs={'name':'egon','age':19}
      3. name为子进程的名称

      方法介绍:

      1. p.start:启动进程,并调用该子进程的p.run()
      2. p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法
      3. p.terminate():强制终止进程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。

      在Windows中使用process注意事项

      在Windows操作系统中,由于没有fork(Linux操作系统中创建进程的机制),在创建子进程的时候会自己动import启动它的这个文件,而在import的时候又执行了整个文件。因此如果将process()直接写在文件中就会无线递归创建子进程报错,所以必须把创建子进程的部分使用if__name___=='__main__'判断保护起来,import的时候,就不会递归运行了。

    3. 使用process模块创建进程

      在一个python进程中开启子进程start方法和并发效果

    4. 守护进程

      会随着主进程的结束而结束

      主进程创建守护进程

      1. 守护进程会在主进程代码执行结束后九终止、
      2. 守护进程内无法再开启子进程,否则抛出异常
    5. socket并发实例

      使用多进程实现socket聊天并发送——server端

      使用多进程实现socket聊天并发——client端

    6. 多进程中其他方法

      进程对象的其他方法:terminate和is_alive

      进程对象的其他属性:pid和name

    进程同步(multiprocess.lock)

    通过学习了异步,让多个任务可以同时在几个进程中并发处理,他们之间的运行没有顺序,一旦开启也不受我们控制。尽管并发编程让我们能更加充分的利用io资源,但是也给我们带来了新的问题:当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题。

    1. 多进程抢占输出资源

      import os 
      import time
      import random
      from multiprocessing import process
      
      def wrok(n):
          print('%s: %s is runing' %(n,os.getpid()))
          time,sleep(random.random)
       print('%s: %s is done' %(n,os.getpid()))
      
      if __name__ == '__main__':
          for i in range(3):
              p=process(target=work,args=(i,))
              p.start
    2. 使用锁维护执行顺序

      import os 
      import time 
      import random
      from multiprocess import process,lock
      
      def work(lock,n):
          lock.acquire()
          print('%s: %s runing' %(n,os.getpid()))
          time.sleep(random.random())
          print('%s: %s is done' %(n,os.getpid()))
          lock.release()
      if __name__=='__main__':
          lock=lock()
          for i in range()
           p=process(targs=work,args=(lock,i))
              p.start()

      上述这种情况虽然使用加锁的形式实现了顺序的执行,但是程序又重新变成串行了,这样确实会浪费了时间,却保证了数据的安全。

    3. 使用锁来保证数据安全

      加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以修改,即串行的修改,没错,速度是慢了,但牺牲了速度却保证了数据安全。

      虽然可以使用文件共享数据实现进程间的通信,但问题是:

      1. 效率低(共享数据基于文件,而文件是硬盘上的数据)
      2. 需要自己加锁处理

      因此我们最好找寻一种解决方案能够兼顾:

      1. 效率高(多个进程共享一块内存的数据)
      2. 帮我们处理好加锁问题。这就是mutiprocessing模块为我们提供的基于消息的ipc通信机制:队列和管道。

      队列和管道都是将数据存放于内存中,队列又是基于(管道+锁)实现的,可以让我们从复杂的锁问题中解脱出来,我们应该尽量避免使用共享数据,尽可能使用消息传递和队列,避免处理复杂的同步和锁问题,而且在进程数目增多时,往往可以获得更好的可获展性。

    我把月亮戳到天上 天就是我的 我把脚踩入地里 地就是我的 我亲吻你 你就是我的
  • 相关阅读:
    获取网站IP地址(Linux,C)
    linux_c_udp_example
    linux_c_tcp_example
    golang-sort
    docker_jenkins
    依赖抽象,而不要依赖具体实现
    网络杂记
    游戏开发中遇到的问题
    随手杂记
    go多态
  • 原文地址:https://www.cnblogs.com/zhulipeng-1998/p/12863936.html
Copyright © 2011-2022 走看看