进程

进程

一.什么是多任务

现代的操作系统(Windows,Mac OS X,Linux,UNIX等)都支持“多任务”。
什么叫做多任务:操作系统同时运行多个任务

  • 单核CPU实现多任务原理:操作系统轮流让各个任务交替执行,QQ执行2us,切换到微信,再执行2us,再切换到陌陌,执行2us······。表面上是每个任务反复执行下去,但是CPU调度执行速度太快了,导致我们感觉就像所有任务都在同时执行一样。

  • 多核CPU实现多任务原理:真正的并行执行多任务只能在多核CPU上实现,但是由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。

并发:看上去一起执行,任务数多于CPU核心数
并行:真正一起执行,任务数小于等于CPU核心数

二、实现多任务的方式:

1.多进程模式(使用较多)
2.多线程模式(使用最多)
3.协程模式 (使用较少)
4.多进程+多线程模式 (容易出错)

生活中与很多场景是同时进行的,比如开车的时候手和脚是同时来控制车。还有一些歌手边唱歌边跳舞。
我们可以理解为我们的大脑控制着我们的身体进行不同的动作。大脑就是cpu,身体的所有支配动作用到的部位为我们的资源。
试想下如果我们的大脑只能控制一个动作完成后才能控制下一个动作,也就是说我们只能先唱完歌再去跳舞,这是不是很尴尬呢?

示例1 一般情况下执行唱歌、跳舞

from time import sleep 
def sing():
    for i in range(3):
        print('我正在唱歌。。。%d'%i)
        sleep(1)

def dance():
    for i in range(3):
        print('我正在跳舞。。。%d'%i)
        sleep(1)
if __name__ == '__main__':
    sing() # 先唱歌
    dance() # 再跳舞
'''
我正在唱歌。。。0
我正在唱歌。。。1
我正在唱歌。。。2
我正在跳舞。。。0
我正在跳舞。。。1
我正在跳舞。。。2'''

示例2 单线程执行函数

from time import sleep
# 单线程执行
def saySorry():
    print("亲爱的,圣诞节快乐!")
    sleep(1)

if __name__ == "__main__":
    for i in range(5):
        saySorry()
"""
# 亲爱的,圣诞节快乐!
# 亲爱的,圣诞节快乐!
# 亲爱的,圣诞节快乐!
# 亲爱的,圣诞节快乐!
# 亲爱的,圣诞节快乐!
"""

示例3 多线程执行函数

import threading
from time import sleep
# 多线程执行
def saySorry():
    print("亲爱的,圣诞节快乐!")
    sleep(1)

if __name__ == "__main__":
    for i in range(5):
        t = threading.Thread(target=saySorry)
        t.start()  # 启动线程,即让线程开始执行
"""
# 亲爱的,圣诞节快乐!
# 亲爱的,圣诞节快乐!
# 亲爱的,圣诞节快乐!
# 亲爱的,圣诞节快乐!
# 亲爱的,圣诞节快乐!
"""

示例4多线程执行唱歌、跳舞1

import threading
from time import sleep,ctime
# 多线程执行唱歌跳舞的多任务。
def sing():
    for i in range(3):
        print("正在唱歌...%d"%i)
        sleep(1)

def dance():
    for i in range(3):
        print("正在跳舞...%d"%i)
        sleep(1)

if __name__ == '__main__':
    print('---开始---:%s'%ctime())

    t1 = threading.Thread(target=sing)
    t2 = threading.Thread(target=dance)

    t1.start()
    t2.start()

    sleep(5)  # 屏蔽此行代码,试试看,程序是否会立马结束?
    print('---结束---:%s'%ctime())

'''
---开始---:Tue May 25 11:26:19 2021
正在唱歌...0
正在跳舞...0
正在唱歌...1
正在跳舞...1
正在唱歌...2
正在跳舞...2
---结束---:Tue May 25 11:26:24 2021
'''

示例5多线程执行唱歌、跳舞2

import threading
from time import sleep,ctime
# 多线程执行唱歌跳舞的多任务。
def sing():
    for i in range(3):
        print("正在唱歌...%d"%i)
        sleep(1)

def dance():
    for i in range(3):
        print("正在跳舞...%d"%i)
        sleep(1)

if __name__ == '__main__':
    print('---开始---:%s'%ctime())

    t1 = threading.Thread(target=sing)
    t2 = threading.Thread(target=dance)

    t1.start()
    t2.start()

    # sleep(5) # 屏蔽此行代码,试试看,程序是否会立马结束?
    print('---结束---:%s'%ctime())

'''---开始---:Tue May 25 11:19:25 2021
正在唱歌...0
正在跳舞...0---结束---:Tue May 25 11:19:25 2021

正在唱歌...1
正在跳舞...1
正在唱歌...2
正在跳舞...2'''

三、什么是进程

1.什么是进程?

对于操作系统而言,一个任务就是一个进程,一个应用就是一个进程。
程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念,而进程是程序在处理机上的一次执行过程,它是一个动态的概念。
进程是系统中程序执行和资源分配的基本单位,每个进程都有自己的数据段、代码段、和堆栈段。
进程是一个具有一定独立功能的程序,一个实体,每一个进程都有它自己的地址空间。

2.进程的状态

进程执行时的间断性,决定了进程可能具有多种状态,事实上,运行中的进程具有以下三种基本状态。
(1)就绪状态(Ready)
(2)运行状态(Running)
(3)阻塞状态(Blocked)

3.单任务现象

# 单任务现象
from time import sleep

def run():
    while True:
        print("haiyan is my wife")
        sleep(2)

if __name__ == "__main__":
    while True:
        print("yangyu is a good man")
        sleep(1)

    run()    # 执行不了.因为上面的循环没有结束。
'''
执行结果:不停打印
yangyu is a good man
yangyu is a good man
yangyu is a good man
yangyu is a good man
yangyu is a good man
yangyu is a good man
yangyu is a good man
yangyu is a good man
...
'''

4.启动进程实现多任务

# 启动进程实现多任务
"""
multiprocessing 库
跨平台版本的多进程模块,提供了一个Process类来代表一个进程对象
"""
from multiprocessing import Process
import os
from time import sleep


# 子进程需要执行的代码
def run(str1):
    while True:
        # os.getpid()获取当前进程的id号
        # os.getppid()获取当前父进程的id号
        print("yangyu is a %s man--%s--%s" % (str1, os.getpid(), os.getppid()))
        sleep(1.2)


if __name__ == "__main__":
    print("主(父)进程启动-%s" % (os.getpid()))
    # 创建子进程
    # target说明进程执行的任务
    p = Process(target=run, args=("nice",))
    # 启动进程
    p.start()

    while True:
        print("yangyu is a good man")
        sleep(1)
'''
主(父)进程启动-2372
yangyu is a good man
yangyu is a good man
yangyu is a nice man--5664--2372
yangyu is a good man
yangyu is a good man
yangyu is a nice man--5664--2372
yangyu is a good man
yangyu is a nice man--5664--2372
yangyu is a good man
yangyu is a nice man--5664--2372
yangyu is a good man
yangyu is a nice man--5664--2372
yangyu is a good man
yangyu is a nice man--5664--2372
yangyu is a good man
yangyu is a good man
yangyu is a nice man--5664--2372'''

5.父子进程的先后顺序

# 父子进程的先后顺序
from multiprocessing import Process
from time import sleep

def run(str1,str2):
    print("子进程启动+%s"%str1)
    sleep(3)
    print("子进程结束+%s"%str2)

if __name__ == "__main__":
    print("父进程启动")

    p = Process(target=run, args=("start","end"))
    p.start()

    # 父进程的结束不能影响子进程,让父进程等待子进程的结束再执行父进程
    p.join()
    print("父进程结束")
'''
父进程启动
子进程启动+start
子进程结束+end
父进程结束
'''

6.多个进程不能共享全局变量

# 多个进程不能共享全局变量
# 在子进程中修改全局变量对父进程中的全局变量没有影响
# 在创建子进程时对全局变量做了一个备份,父进程中的子进程中的num是完全不同的两个变量
from multiprocessing import Process
num = 100
def run():
    print("子进程开始")
    global num  # num = 100
    num += 1
    print(num)
    print("子进程结束")

if __name__ == "__main__":
    print("父进程开始")
    p = Process(target=run)
    p.start()
    p.join()
    print("父进程结束--%d"%num)
'''
父进程开始
子进程开始
101
子进程结束
父进程结束--100
'''

7.启动多个子进程

# 启动多个子进程
from multiprocessing import Pool
import os,time
def run(name):
    print("子进程%d启动--%s" % (name, os.getpid()))
    start = time.time()
    time.sleep(3)
    end = time.time()
    print("子进程%d结束--%s--耗时%.2f" % (name, os.getpid(), end-start))

if __name__ == "__main__":
    t1 = time.time()
    print("父进程启动")
    # 创建多个进程
    # 进程池
    # 表示可以同时执行的进程数量
    # Pool默认大小是cpu核心线程数,我的笔记本电脑是2核4线程(这里的线程就同时执行的进程),Pool()默认为4,默认同时执行4进程,总耗时为18.2s;改为2,总耗时为32.5s;改为8,总耗时14.1s;改为20,总耗时20.35s。所有一般就用核心数*线程数(2*4=8),执行速度最快。
    pp = Pool(8)
    for i in range(20):
        # 创建进程,放入进程池同意管理
        pp.apply_async(run, args=(i,))
    # 在调用join之前必须先调用close,调用close之后就不能再继续添加新的进程了
    pp.close()
    # 进程池对象调用join,会等待进程池中所有的子进程结束完毕再去执行父进程
    pp.join()
    print("父进程结束,总耗时为%s"%(time.time()-t1))
'''
父进程启动
子进程0启动--9048
子进程1启动--3648
子进程2启动--7180
子进程3启动--7888
子进程4启动--8228
子进程5启动--8664
子进程6启动--8688
子进程7启动--9432
子进程0结束--9048--耗时3.01
子进程8启动--9048
子进程1结束--3648--耗时3.01
子进程9启动--3648
子进程2结束--7180--耗时3.01
子进程10启动--7180
子进程3结束--7888--耗时3.01
子进程11启动--7888
子进程4结束--8228--耗时3.01
子进程12启动--8228
子进程5结束--8664--耗时3.01
子进程13启动--8664
子进程6结束--8688--耗时3.01
子进程14启动--8688
子进程7结束--9432--耗时3.01
子进程15启动--9432
子进程8结束--9048--耗时3.07
子进程16启动--9048
子进程9结束--3648--耗时3.01
子进程17启动--3648
子进程10结束--7180--耗时3.01
子进程18启动--7180
子进程11结束--7888--耗时3.01
子进程19启动--7888
子进程12结束--8228--耗时3.01
子进程13结束--8664--耗时3.01
子进程14结束--8688--耗时3.01
子进程15结束--9432--耗时3.01
子进程16结束--9048--耗时3.01
子进程17结束--3648--耗时3.01
子进程18结束--7180--耗时3.04
子进程19结束--7888--耗时3.01
父进程结束,总耗时为14.196025133132935
'''

8.多进程文件拷贝

1.普通文件拷贝

# 实现文件的拷贝
import os, time
def copyFile(rPath, wPath):
    fr = open(rPath, "rb")
    fw = open(wPath, "wb")
    context = fr.read()
    fw.write(context)
    fr.close()
    fw.close()

path = r"F:\PycharmProjects\Project\进程\file1\1905热门电影图片"
toPath = r"F:\PycharmProjects\Project\进程\file2"

# 读取path下的所有文件
fileList = os.listdir(path)

# 启动for循环去处理每个文件
start = time.time()
for fileName in fileList:
    copyFile(os.path.join(path,fileName), os.path.join(toPath, fileName))
end = time.time()
print("总耗时:%0.2f" % (end-start))  # 总耗时:14.68

2.多进程文件拷贝

import os, time
from multiprocessing import Pool
# 实现文件的拷贝
def copyFile(rPath, wPath):
    fr = open(rPath, "rb")
    fw = open(wPath, "wb")
    context = fr.read()
    fw.write(context)
    fr.close()
    fw.close()

path = r"F:\PycharmProjects\Project\进程\file1\1905热门电影图片"
toPath = r"F:\PycharmProjects\Project\进程\file2"

if __name__ == "__main__":
    # 读取path下的所有文件
    fileList = os.listdir(path)
    start = time.time()
    pp = Pool(4)
    for fileName in fileList:
        pp.apply_async(copyFile, args=(os.path.join(path, fileName), os.path.join(toPath, fileName)))
    pp.close()
    pp.join()
    end = time.time()
    print("总耗时:%0.2f" % (end - start))  # 总耗时:11.40

9.封装进程对象

1.创建yangyuProcess.py文件

from multiprocessing import Process
import os, time

class YangyuProcess(Process):
    def __init__(self, name):
        Process.__init__(self)
        self.name = name

    def run(self):
        print("子进程(%s-%s)启动" % (self.name, os.getpid()))

        # 子进程的功能
        time.sleep(3)

        print("子进程(%s-%s)结束" % (self.name, os.getpid()))

2.from yangyuProcess import YangyuProcess

from yangyuProcess import YangyuProcess

if __name__ == "__main__":
    print("父进程启动")
    # 创建子进程
    p = YangyuProcess("test")
    # 自动调用p进程对象的run方法
    p.start()
    p.join()
    print("父进程结束")
'''
打印结果:
父进程启动
子进程(test-3476)启动
子进程(test-3476)结束
父进程结束
'''
"""
这样写的好处:子进程的方法不用和父进程的方法写在一起,让主程序结构更清晰。
"""

10.进程间的通信

1.示例1

from multiprocessing import Process, Queue
import os,time

def write(q):
    print("启动写子进程%s"%(os.getpid()))
    for chr in ["A","B","C","D"]:
        q.put(chr)
        time.sleep(1)
    print("结束写子进程%s"%(os.getpid()))

def read(q):
    print("启动读子进程%s" % (os.getpid()))
    while True:
        value = q.get(True)
        print("value=" + value)
    print("结束读子进程%s" % (os.getpid()))


if __name__ == "__main__":
    # 父进程创建队列,并传给子进程
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))

    pw.start()
    pr.start()

    pw.join()
    pr.terminate()  # pr进程里是个死循环,无法等待其结束,只能强制结束

    print("父进程结束")

'''
启动写子进程7752
启动读子进程7264
value=A
value=B
value=C
value=D
结束写子进程7752
父进程结束'''

2.示例2

from multiprocessing import Process, Queue
import os,time

def write(q):
    print("启动写子进程%s"%(os.getpid()))
    for chr in ["A","B","C","D"]:
        q.put(chr)
        print(chr)
    print("结束写子进程%s"%(os.getpid()))

def read(q):
    print("启动读子进程%s" % (os.getpid()))
    while not q.empty():
        value = q.get(True)
        print("value=" + value)
        time.sleep(1)
    print("结束读子进程%s" % (os.getpid()))


if __name__ == "__main__":
    print("父进程开始")
    # 父进程创建队列,并传给子进程
    q = Queue(4)
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))

    pw.start()
    pr.start()
    pw.join()
    pr.join()
    print("父进程结束")

'''
父进程开始
启动写子进程8228
A
B
C
D
结束写子进程8228
启动读子进程7472
value=A
value=B
value=C
value=D
结束读子进程7472
父进程结束
'''
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值