Python 基础 进程

一  操作系统 

1 为什么要有操作系统

计算机是由一个或者多个处理器CPU,内存条,磁盘,键盘,鼠标,显示器,以及各种其他输入输出设备组成的机器。如果我们想让自己的应用程序运行在计算机上,我们需要了解

计算机中所有的细节例如处理器怎么运行,内存的分配等等。每位程序员不可能掌握所有系统实现的细节,并且管理优化这些部件是一件挑战性极强的工作。因此就出现了操作系统(操作系统也是一个软件)。

操作系统的定义:操作系统是一个用来协调、管理和控制计算机硬件和软件资源的系统程序,它位于硬件和应用程序之间。起承上启下的作用。我们写好的程序只需要给操作系统即可,

操作系统会给我们的程序分配内存等等一些操作。

二  多任务

多任务就是同一时刻多个任务同时执行,例如开演唱会时明星一边唱歌一边跳舞,开车时眼睛看路手操作方向盘。这些都是多任务场景。

对于电脑来说多任务就是同时运行多个应用程序,例如qq、微信、浏览器等等同时在电脑上运行。

1  电脑实现多任务的原理

例如qq、微信、网易云音乐播放器3个应用程序能同时运行是因为CPU在多个应用程序之间高速切换的结果,当CPU切换到了qq,就用0.01s时间(时间不确定)执行qq程序,然后再随机切换到其他应用程序在执行一段时间,CPU在多个程序之间快速往复执行,我们的肉眼根本感觉不到卡顿,导致我们的错觉感觉是同时运行的效果。如果电脑运行了多个程序有时候会出现卡顿现象是因为cup切换不过来了。

 

2 单核 双核 CPU 介绍

单核CPU 指的是CPU中有一个核心(形象理解CPU是人的头,核心是头里面包含的大脑),用来处理程序。

双核/四核CPU 就是CPU中有2个或者4个核心,(1个脑袋中长了2个大脑或者4个大脑),相当于有2个单核CPU或者是4个单核CPU

在python中实现多任务有3种方式,进程、线程、协程。

三  进程 

1什么是进程

我们想通过酷我听歌,具体的过程应该是先找到酷我应用程序,然后双击就会播放音乐。

当我们双击的时候,操作系统将程序装载到内存中,操作系统为它分配资源,然后才能运行。运行起来的应用程序就称之为进程。也就是说当程序不运行的时候我们称之为程序,当程序运行起来他就是一个进程。通俗的理解就是不运行的时候是程序,运行起来就是进程。程序和进程的对应关系是:程序只有一个,但是进程可以有多个。

2 创建多进程

import time

def sing():
    for i in range(3):
        print('...正在唱歌...',i)
        time.sleep(1)

def dance():
    for i in range(3):
        print('...正在跳舞'...,i)
        time.sleep(1)

def main():
    sing()
    dance()

if __name__ == '__main__':
    main()

花费了6s 的时间

2 使用进程让唱歌和跳舞一起执行。

import time
import multiprocessing  #导入  多进程模块


def sing():
    for i in range(3):
        print('...正在唱歌...')
        time.sleep(1)

def dance():
    for i in range(3):
        print('...正在跳舞...')
        time.sleep(1)

def main():
    p1 = multiprocessing.Process(target = sing)    #创建进程p1 执行sing函数
    p2 = multiprocessing.Process(target = dance)   #创建进程p2 执行sing函数
    p1.start()  #开始执行进程p1
    p2.start()  #开始执行进程p2
    #  开启了2个子进程p1,p2

if __name__ == '__main__':
    main()

花费了3秒的时间,提升了程序的运行效率

程序理解:

主进程从main()开始执行,执行main函数体,当执行到p1.start()时,创建一个子进程,p1子进程中的代码和主进程相同,只是程序执行的开始是 sing函数体。

主进程执行到p2.start()时,同样复制一份主进程代码从danc函数体开始执行。

import multiprocessing
import time

g_num = 10

def test1():
    global g_num
    g_num += 1
    print('test1--->>',g_num)

def test2():
    print('test2--->>',g_num)

def main():
    p1 = multiprocessing.Process(target=test1)
    p2 = multiprocessing.Process(target=test2)
    p1.start()
    p2.start()

if __name__ == '__main__':
    main()

3 进程的状态

在程序运行的过程中,由于被操作系统的调度算法控制,程序会进入几个状态:就绪,运行和阻塞。

(1)就绪(Ready)状态

当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态。

(2)执行/运行(Running)状态当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。

(3)阻塞(Blocked)状态正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等。

4  进程之间的通讯

刚才我们说了进程可以理解为复制了一份程序有加载到了内存了,进程之间是独立的,如果我想两个进程之间进行通讯怎么办呢?我们可以使用Queue 队列,队列是一种先进先出的存储数据结构,就比如排队上厕所一个道理。

两个进程通讯,就是一个子进程往queue中写内容,另一个进程从queue中取出数据。就实现了进程间的通讯了。

(1) queue 队列

1 创建 queue队列对象

q = multiprocessing.Queue(3)  # 3表示只能存放3个数据

参数 :maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。

返回值q 是队列对象

q = multiprocessing.Queue(3)  # 3表示只能存放3个数据

参数 :maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。

返回值q 是队列对象

  1. put()方法 ,向队列中存放数据。如果队列已满,此方法将阻塞至有空间可用为止。
  2. get()返回q中的一个项目。如果q为空,此方法将阻塞,直到队列中有项目可用为止。
  3. get_nowait(): 不等待,直接抛出异常
  4. full()如果q已满,返回为True
  5. q.empty() 如果调用此方法时 q为空,返回True
import multiprocessing
# 可以写参数,如果不写默认可以表示放任意多个数据
# 指定参数后,只能存放指定的个数的数据

q = multiprocessing.Queue(3)
q.put('哈哈')
q.put('123')
q.put([1,2,3])
#q.put('lala')   #阻塞了,直到有数据被使用后,才能继续放进去,否则一值等待
#q.put_notwait('haha')   #程序会报错  队列满了
print(q.get())
print(q.get())
print(q.get())
#q.get_notwait()  #同q.put_notwait

q.empty() #判断队列中是否还有数据  True 或者 False
q.full()  #判断队列是否满了   True 或者 False

进程的传递参数

import time
import multiprocessing

def sing(num):
    for i in range(num):
        print('...正在唱歌...',i)
        time.sleep(1)

def dance(num):
    for i in range(num):
        print('...正在跳舞...',i)
        time.sleep(1)

def main()
    p1 = multiprocessing.Process(target=sing,args=(3,))
    # 传递参数,传递的是元组 所以3 后面要加逗号
    p2 = multiprocessing.Process(target=dance,args=(3,))
    p1.start
    p2.start

if __name__ =='__main__':
    main()
    print(''程序结束了)

练习 1 使用queue模拟多任务下载和处理数据

from multiprocessing import Process,Queue

def download_data(q):
    lst = ['a','b','c']
    for i in lst:
        q.put(i)  #将下载的数据保存到队列中
    print('下载的数据')

def process_data(q):
    for i in range(q.qsize()):
        print(q.get())
    print('处理数据')

def main():
    #先创建一个队列
    q = Queue()
    #创建两个子进程
    q1 = Process(target=download_data,args=(q,))
    q2 = Process(target=download_data,args=(q,))
    q1.start()
    q2.start()

if __name__ == '__main__':
    main 

5.进程池

当需要创建的子进程数量不多时,我们可以直接利用multiporcessing中的Process动态生成多个进程,但是如果现在有100个任务需要处理,那我们需要多少个子进程呢,如果我们创建100个子进程也可以实现,但是资源比较浪费。我们也可以创建指定个数个子进程,例如只创建10个子进程,让着10个子进程重复的执行任务,这样就节约了资源。

就比如我们去景区湖上游玩,游船是重复利用的。

我们可以使用multiprocessing模块提供的Pool类,也就是进程池,可以到达进程重复利用。泸沽岛

创建进程池对象的时候可以指定一个最大进程数,当有新的请求提交到进程池中,如果池中的进程数还没有满,那么就会创建一个新的进程用来执行该请求,但是如果池中的进程数满了,该请求就会等待,知道进程池中的进程有结束的了,才会使用这个结束的进程来执行新的任务。

 

join 主进程等待所有子进程执行完毕,必须在close之后。

close 等待所有进程结束才关闭线程池

 

 

猜你喜欢

转载自blog.csdn.net/weixin_44303465/article/details/86582590
今日推荐