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

    一.什么是并发编程?

    并发指的是多个任务可以被同时执行.

    并发编程就是找到一种方案,让一个程序中的多个任务可以同时被处理.

     

    二.什么是进程?

    进程指的是正在运行的程序,是一系列程序的统称,也是操作系统在调度和进行资源分配的基本单位.

    进程是实现并发的一种方式

     

    三.多进程的实现原理:多道技术

    操作系统的发展历史:

    第一代计算机:真空管和穿孔卡片

    特点:没有操作系统概念,所有程序直接操作硬件

     

    第二代计算机:晶体管和批处理系统

    特点:设计人员,生产人员,操作人员,程序人员,维护人员直接有了明确的分工,计算机被锁在专用的空调房间中,由专业的操作人员运行,这便是'大型机'.

     

    第三代计算机:集成电洛芯片和多道程序设计

    多道技术中的多道指的是多个程序,多道技术的实现是为了解决多个程序竞争或者说共享同一资源(比如cpu)的有序调度问题,解决方式即多路复用,多路复用分为时间上的复用和空间上的复用.

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

    时间上的复用:当一个程序在等待I/O或者占用CPU时间过长时,操作系统就可以控制进程的切换,这样另一个程序就可以使用CPU,如果内存中可以同时存放足够多的作业,则cpu的利用率可以接近100%.

    空间上的复用最大问题:程序之间的内存必须分割,这种分割需要在硬件层面实现,由操作系统控制.

     

    多道技术案例:生活中我们进程会同时做多个任务,但是本质上一个人是不可能同时执行多个任务.

    例:吃法和打游戏同时进行,本质是在两个任务之间切换执行,吃一口饭然后打打游戏,打打游戏再吃一口饭.

     

    多道技术是在不同任务之间切换执行,由于计算机的切换速度非常快,所以用户是没有任何感觉的,看起来就像是两个任务都在执行,但是另一个问题是,仅仅是切换还不行,还需要在切换前保存当前状态,切换回来时恢复状态,这些切换和保存都是需花费时间的,如果对于一些不会出现IO操作的程序而言,切换不仅不能提高效率,反而降低效率.

    例如:做基本加减乘除运算

     

    第四代计算机:个人计算机

    第四代也就是我们常见的操作系统,大多数具备图形化界面,如:Windows,macOS,CentOS等

     

    四.进程与程序

    进程是正在运行的程序,程序是程序员编写的一堆代码,也就是一堆字符,当这堆代码被系统加载到内存中并执行时,就有了进程。

    查看进程:在CMD中输入tasklist查看操作系统所有的进程,在cmd中输入tasklist | findstr +程序名 查看该程序下的所有进程.

     

    并发与并行

    并发指的是多个事件同时发生 例如洗衣服和做饭,同时发生了,但本质上是两个任务在切换,给人的感觉是同时在进行,也被称为伪并行

    并行指的是多个事件都在进行着 例如:一个人在写代码,一个人在写书,cpu双核,四核,八核同时运行多个程序,这个是真正的并行

     

    阻塞与非阻塞

    阻塞状态是因为程序遇到了IO操作,或是sleep,导致后续的代码不能被CPU执行

    非阻塞与之相反,表示程序正在正常被CPU执行

    进程有三种状态:就绪态,运行态,和阻塞态 就绪态和阻塞态就是阻塞,运行态是非阻塞.

     

    五.进程的相关理论

    进程的创建:

    1.系统初始化

    2.一个进程在运行过程中开启了子进程

    3,用户的交互请求,而创建了一个子进程(双击暴风影音)

    4.一个批处理作业的初始化(只在大型机的批处理系统中使用)

     

    进程的销毁

    1. 正常退出(自愿,如用户点击交互式页面的叉号,或程序执行完毕调用发起系统调用正常退出,在linux中用exit,在windows中用ExitProcess)

    2. 出错退出(自愿,python a.py中a.py不存在)

    3. 严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,可以捕捉异常,try...except...)

    4. 被其他进程杀死(非自愿,如kill -9)

     

    unix和windows创建进程

    相同点:

    进程创建后,父进程和子进程有各自不同的地址空间(多道技术要求物理层面实现进程之间内存的隔离),任何一个进程的在其地址空间中的修改都不会影响到另外一个进程。

    不同点:

    1. UNIX子进程会将父进程内存地址中的值原模原样的拷贝到子进程内存中去

    2. windows在创建子进程时不仅会拷贝父进程的数据还会将父进程的代码再执行一次.导致重复创立多个子进程.所以一定要将创立子进程的代码放到main(只有右键运行它才会运行,加载不会运行)的下面.

     

    六.PID和PIDD

    os.getpid() #获取自己进程的id

    os.getppid() #获取父进程的id

     七.开启进程的两种方式

    方法一:实例化Process
    from multiprocessing import Process
    import os
    def task(name):
      print(name)
      print('self',os.getpid())
      print('parent',os.getppid())
      print('这是子进程')
    if __name__ == '__main__':
      print('self',os.getpid())
      print('parent',os.getppid())
      p = Process(target = task,name='这是子进程',args=('henry',)) #实例化Process
      p.start() #给操做系统发送通知,要求操作系统开启子进程

    方法二:继承Process 并覆盖run方法
    from multiprocessing import Process
    class MyProcess(Process):
      def __init__(self,inter):
        super().__init__()
        self.inter = inter
      # 子类中的方法 只有run会被自动执行
      def run(self):
        print('下载网址%s'%self.inter)
    if __name__ == '__main__':
      p = MyProcess('www.22ccc.com')
      p.start()

    八.进程间内存相互隔离

    from multiprocessing import Process
    import time
    a = 100
    def task():
      global a
      a = 0
      print('子进程的a:%s'%a) #结果:0
    if __name__ == '__main__':
      p = Process(target=task)
      p.start()
      time.sleep(0.5)
      print('父进程的a:%s'%a) #结果:100

    九.join函数 父进程等待子进程结束

    from multiprocessing import Process
    import time
    def task():
      print('上传文件...')
      time.sleep(3)
      print('上传结束...')
    if __name__ == '__main__':
      p = Process(target=task)
      p.start()
      p.join() #本质上是提高了子进程的优先级,当cpu在切换的时候,优先切换子进程
      print('上传文件成功!')

    from multiprocessing import Process
    import time
    def task(num):
      print('这是子进程%s'%num)
      time.sleep(2)
    if __name__ == '__main__':
      start_time = time.time()
      ps = []
      for i in range(5):
        p = Process(target=task,args=(i,))
        p.start()
        ps.append(p)
      for p in ps: #将所有进程指令一同发出
        p.join()
      print(time.time()-start_time)
      print('over')

    十.Process常用属性

    from multiprocessing import Process
    import time
    def task():
      time.sleep(3)
      print('执行完毕')
    if __name__ == '__main__':
      p = Process(target=task,name='henry')
      p.start()
      print(p.name) #获取名字
      print(p.is_alive())#子进程没有结束True,子进程结束False
      p.terminate()#终止这个程序
      print(p.pid)#获取进程自己的id
      p.daemon #守护进程

    十一.孤儿进程和僵尸进程

    孤儿进程是指父进程已经终止了,但是自己还在运行,是无害的
    孤儿进程会自定过继给操作系统

    僵尸进程是指子进程执行完成所有任务 已经终止了但是还残留一些信息(进程id 进程名)
    但是父进程没有去处理这些残留信息 导致残留信息占用系统内存 僵尸进程时有害的

    当出现大量的僵尸进程时 会占用系统资源 可以把它父进程杀掉 僵尸就成了孤儿 操作系统会负责回收数据

  • 相关阅读:
    MongoDB
    新公司管理经营
    剪辑理论
    色彩理论
    商业模式
    电影手法
    [好文转载] 每个程序员都应该学习使用Python或Ruby
    File类递归
    【CF1447】div2复盘
    【心得体会】11.9-11.15
  • 原文地址:https://www.cnblogs.com/lizeqian1994/p/10191899.html
Copyright © 2011-2022 走看看