zoukankan      html  css  js  c++  java
  • Python——进程


    进程

    什么是操作系统:
    • 操作系统(简称OS):是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他软件都必须在操作系统的支持下才能运行
      操作系统可以使用户有一个好的工作环境,屏蔽硬件物理特性和操作细节,为用户使用计算机提供了便利。同时为其它软件的开发提供必要的服务和相应的接口等
    • 操作系统管理着计算机硬件资源,同时按照应用程序的资源请求,分配资源,如:划分CPU时间,内存空间的开辟,调用打印机等
    生活中常见的操作系统:

    windows
    MacOS
    android
    ios

    服务器端常用操作系统:服务器操作系统一般指的是安装在大型计算机上的操作系统,比如Web服务器、应用服务器和数据库服务器等

    Unix
    1965年之前的时候,电脑并不像现在一样普遍,不是一般人能接触到的,除非是军事或者学院的研究机构,而且当时大型主机至多能提供30台终端(30个键盘、显示器),连接一台电脑

    为了解决数量不够用的问题:

    • 1965年左后由贝尔实验室、麻省理工学院以及通用电气共同发起了Multics项目,想让大型主机支持300台终端
    • 1969年前后这个项目进度缓慢,资金短缺,贝尔实验室退出了研究
    • 1969年从这个项目中退出的Ken
      Thompson当时在实验室无聊时,为了让一台空闲的电脑上能够运行“星际旅行”游戏,在8月份左右趁着其妻子探亲的时间,用了1个月的时间编写出了
      Unix操作系统的原型、
    • 1970年,美国贝尔实验室的 Ken Thompson,设计出很简单且很接近硬件的 B语言,并且他用B语言写了第一个UNIX操作系统
    • 因为B语言的跨平台性较差,为了能够在其他的电脑上也能够运行这个非常棒的Unix操作系统,Dennis Ritchie和Ken
      Thompson 从B语言的基础上准备研究一个更好的语言
    • 1972年,美国贝尔实验室的 Dennis Ritchie在B语言的基础上最终设计出了一种新的语言,C语言
    • 1973年初,C语言的主体完成。Thompson和Ritchie开始用它完全重写了现在的Unix操作系统
    Minix
    • UNIX 是一个强大的多用户、多任务操作系统,但是因为政策改变,在Version 7
      Unix推出之后,发布新的使用条款,将UNIX源代码私有化,在大学中不再能使用UNIX源代码
    • 塔能鲍姆教授为了能在课堂上教授学生操作系统运作的细节,决定在不使用任何AT&T的源代码前提下,自行开发与UNIX兼容的操作系统,以避免版权上的争议。他以小型UNIX(mini-UNIX)之意,将它称为MINIX。
    Linux
    • 因为Minix只是教学使用,因此功能并不强,因此Torvalds(林纳斯·托瓦兹)编写了Linux内核。严格来讲,Linux这个词本身只表示Linux内核,但在实际上人们已经习惯了用Linux来形容整个基于Linux内核的操作系统
    多任务处理:使得计算机可以同时处理多个任务:

    听歌的同时QQ聊天、办公、下载文件
    实现方式:多进程、多线程
    在这里插入图片描述

    串行,并行,并发

    并发:多个进程轮流执行,(多个程序来回的切换)cpu来回切换(单核CPU)
    串行:如果有多个程序,完整执行一个,才能执行下一个。
    并行:指多个进程同时执行(多核cpu)

    程序:是一个指令的集合
    进程:

    • 正在执行的程序;或者说:当你运行一个程序,你就启动了一个进程 编写完的代码,没有运行时,称为程序,正在运行的代码,称为进程
      程序是死的(静态的),进程是活的(动态的)
    • 操作系统轮流让各个任务交替执行 ,由于CPU的执⾏速度实在是太快了, 我们感觉就像所有任务都在同时执行一样
    总结:

    进程:程序运行的过程。
    多进程中, 每个进程中所有数据(包括全局变量) 都各有拥有一份, 互不影响

    多进程:

    模拟多任务处理:一边唱歌一边跳舞
    from time import sleep
    def sing():
    for i in range(3):
    print("正在唱歌")
    dance()
    sleep(1)

    def dance():
    print("正在跳舞")
    if name == 'main':
    sing()

    • 程序开始运行时,首先会创建一个主进程

    • 在主进程(父进程)下,我们可以创建新的进程(子进程),子进程依赖于主进程,如果主进程结束,程序会退出

    • Python提供了非常好用的多进程包multiprocessing,借助这个包,可以轻松完成从单进程到并发执行的转换

    from multiprocessing import Process 
    def foo(): 
    	print("in the foo") 
    if __name__ == "__main__": 
    	p = Process(target=foo)#args:参数以元组的形式存在
    	p.start()#启动子进程,并且调用子进程的run方法,就绪状态
    	p.join()# 主进程阻塞, 等待子进程的退出(主进程等待子进程终止)其中有参数代表超时时间,
    
    

    解析:name == "main"

    • 在Windows中运行的时候,每创建一个进程,都在子进程所在的空间中导入主进程(所有的代码即
      import.py文件导入到子进程中,主进程有的子进程都有)如果把这一行去掉,即主进程代码中包含了子 进程创建对象,执行p =
      Process(target=foo)开辟空间,因为创建子进程,就会导入代码,就会再次
      创建自己就会形成递归,为了避免这个问题,把__name__ == "main"加上,
    • 为什么不出错了哪,因 为if做条件判断,只有if成立才会执行下面的代码,其中__name__存放的是当前文件的文件名,
      main(当前文件正在运行那么该文件名就是main)判断系统变量name是不是main,其中把.py文件当 做程序去运行一遍,即name=main,当前文件被执行的时候name的值是main,当被导入到其它文件中就不
      是main了,在子进程里.py文件是导入进来的,即在子进程里不成立,不执行了,避免了递归调用。
    一个.py文件有两种使用方式 :

    1.直接当成程序去运行。
    2.作为模块导入到其它包里面。

    总结:

    • if name == “main”:说明
      一个python的文件有两种使用的方法,第一是直接作为程序执行,第二是import到其他的python程序中被调用(模块重用)执行。
    • 因此if name == 'main': 的作用就是控制这两种情况执行代码的过程,name
      是内置变量,用于表示当前模块的名字 在if name == 'main':
      下的代码只有在文件作为程序直接执行才会被执行,而import到其他程序中是不会被执行的
    • 在 Windows 上,子进程会自动 import 启动它的这个文件,而在 import 的时候是会执行这些语句的。如果不加if
      name == "main":的话就会无限递归创建子进程 所以必须把创建子进程的部分用那个 if 判断保护起来 import 的时候 name 不是 main ,就不会递归运行了
    Process(target , name , args) 参数介绍:
    • target表示调用对象,即子进程要执行的任务
    • args表示调用对象的位置参数元组,args=(1,)
    • name为子进程的名称

    Process类常用方法:

    • p.start():启动进程,并调用该子进程中的p.run()
    • p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法
    • p.terminate()(了解)强制终止进程p,不会进行任何清理操作
    • p.is_alive():如果p仍然运行,返回True.用来判断进程是否还在运行
    • p.join([timeout]):主进程等待p终止,timeout是可选的超时时间

    Process类常用属性:

    • name: 当前进程实例别名, 默认为Process-N, N为从1开始递增的整 数;
    • pid: 当前进程实例的PID值

    全局变量在多个进程中不共享:进程之间的数据是独立的,默认情况下互不影响

    from multiprocessing import Process
    num = 1
    def run1():
        global num
        num += 5
        print("子进程1运行中,num = %d"%(num))
    def run2():
        global num
        num += 10
        print("子进程2运行中,num = %d"%(num)) 
    

    创建进程的方式2:

    创建新的进程还能够使用类的方式, 可以自定义一个类, 继承Process类, 每次实例化这个类的时候, 就等同于实例化一个进程对象

    import multiprocessing
    import time
    class ClockProcess(multiprocessing.Process):
    def run(self):
            n = 5
            while n > 0:
                print(n)
                time.sleep(1)
                n -= 1
    if __name__ == '__main__':
        p = ClockProcess()
        p.start()
        p.join()
    

    进程池:

    进程池:用来创建多个进程

    • 当需要创建的子进程数量不多时, 可以直接利⽤multiprocessing中的Process动态生成多个进程,
      但如果是上百甚至上千个目标, 手动的去创建进程的工作量巨大, 此时就可以用到multiprocessing模块提供的Pool
    • 初始化Pool时, 可以指定一个最大进程数, 当有新的请求提交到Pool中时,如果池还没有满, 那么就会创建一个新的进程用来执行该请求;
      但如果池中的进程数已经达到指定的最大值, 那么该请求就会等待, 直到池中有进程结束, 才会创建新的进程来执行

    进程池:

    from multiprocessing import Pool
    import random,time
    
    def work(num):
        print(random.random()*num)
        time.sleep(3)
    if __name__ == "__main__":
        po = Pool(3)        #定义一个进程池,最大进程数为3,默认大小为CPU核数
        for i in range(10):
            po.apply_async(work,(i,))      #apply_async选择要调用的目标,每次循环会用空出来的子进程去调用目标
        po.close()       #进程池关闭之后不再接收新的请求
        po.join()         #等待po中所有子进程结束,必须放在close后面
    
    在多进程中:主进程一般用来等待,真正的任务都在子进程中执行
    
    multiprocessing.Pool常用函数解析:
    • apply_async(func[, args[, kwds]]) : 使用非阻塞方式调用func(并行执行,
      堵塞方式必须等待上一个进程退出才能执行下一个进程) , args为传递给func的参数列表, kwds为传递给func的关键字参数列表;
    • apply(func[, args[, kwds]])(了解即可) 使用阻塞方式调用func
    • close(): 关闭Pool, 使其不再接受新的任务;
    • join(): 主进程阻塞, 等待子进程的退出, 必须在close或terminate之后使用;
    进程间通信-Queue :
    • 多进程之间,默认是不共享数据的
    • 通过Queue(队列Q)可以实现进程间的数据传递
    • Q本身是一个消息队列
    • 如何添加消息(入队操作):
    from multiprocessing import Queue
    q = Queue(3)      #初始化一个Queue对象,最多可接受3条消息
    q.put(“消息1”)     #添加的消息数据类型不限
    q.put("消息2")
    q.put("消息3")
    print(q.full())
    
    • 可以使用multiprocessing模块的Queue实现多进程之间的数据传递
    • 初始化Queue()对象时(例如: q=Queue()) , 若括号中没有指定最⼤可接收 的消息数量, 或数量为负值,
      那么就代表可接受的消息数量没有上限
    • Queue.qsize(): 返回当前队列包含的消息数量
    • Queue.empty(): 如果队列为空, 返回True, 反之False
    • Queue.full(): 如果队列满了, 返回True,反之False
    • Queue.get([block[, timeout]]): 获取队列中的一条消息, 然后将其从列队中移除, block默认值为True
    • 如果block使用默认值, 且没有设置timeout(单位秒) , 消息列队如果为空, 此时程序将被阻塞(停在读取状态) ,
      直到从消息列队读到消息为止
    • 如果设置了timeout, 则会等待timeout秒, 若还没读取到任何消息, 则抛出"Queue.Empty"异常
      如果block值为False, 消息列队如果为空, 则会立刻抛出“Queue.Empty”异常
    Queue.get_nowait(): 相当Queue.get(False)
    Queue.put(item,[block[, timeout]]): 将item消息写入队列, block默认值 为True
    • 如果block使用默认值, 且没有设置timeout(单位秒) , 消息列队如果已 经没有空间可写⼊, 此时程序将被阻塞(停在写入状态), 直到从消息列队腾出空间为止;
    • 如果设置了True和timeout, 则会等待timeout秒, 若还没空间, 则抛出"Queue.Full"异常
      如果block值为False, 消息列队如果没有空间可写入, 则会立刻抛出"Queue.Full"异常
    Queue.put_nowait(item): 相当Queue.put(item, False);
    from multiprocessing import Queue, Process
    import time
    
    def write(q):
        for value in ["a","b","c"]:
            print("开始写入:",value)
            q.put(value)
            time.sleep(1)
    
    def read(q):
        while True:
            if not q.empty():
                print("读取到的是",q.get()) 
                time.sleep(1)
            else:
                break
    if __name__ == "__main__":
        q = Queue()
        pw = Process(target=write, args=(q,))
        pr = Process(target=read, args=(q,))
        pw.start()
        pw.join()#等待接收完毕
        pr.start()
        pr.join()
        print("接收完毕!")
    
    
    问题:
    如果有两个接收方怎么办?(多任务之间配合)
    
    • 进程池创建的进程之间通信:如果要使用Pool创建进程,
      就需要使用multiprocessing.Manager()中的Queue()而不是multiprocessing.Queue()
    • 否则会得到一条如下的错误信息:RuntimeError: Queue objects should only be shared between processes through inheritance.
    from multiprocessing import Manager,Pool
    import time
    
    def writer(q):
        for i in "welcome":
            print("开始写入",i)
            q.put(i)
    
    def reader(q):
        time.sleep(3)
        for i in range(q.qsize()):
            print("得到消息",q.get())
    if __name__ == "__main__":
        print("主进程启动")
        q = Manager().Queue()
        po = Pool()
        po.apply_async(writer,(q,))
        po.apply_async(reader,(q,))
        po.close()
        po.join()
    
    有志者,事竟成,破釜沉舟,百二秦关终属楚; 苦心人,天不负,卧薪尝胆,三千越甲可吞吴。 想到与得到中间还有两个字——做到。
  • 相关阅读:
    课后作业-阅读任务-阅读笔记-4
    《团队--学生成绩管理-阶段互评》
    《团队-学生成绩管理-阶段互评》
    团队编程项目作业4-开发文档
    阅读任务--阅读提问-3
    课后作业-阅读任务-阅读笔记3
    课后作业-阅读任务-阅读提问-3
    课后作业-阅读任务-阅读笔记-3
    结对编程项目作业5
    结对编程项目作业4
  • 原文地址:https://www.cnblogs.com/huoxc/p/13304390.html
Copyright © 2011-2022 走看看