进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。
对于操作系统来说,一个任务就是一个进程。比方说打开浏览器就是启动一个浏览器的进程,在打开一个记事本就启动一个记事本进程,如果打开两个记事本就启动两个记事本进程。
进程可以在任务管理器中进行查看
进程创建时需导入from multiprocessing import Process,创建进程是使用类Process进行
运行进程时用start()方法,代表启动进程并执行;不能使用run()方法,run()代表执行了任务但没有启动进程
terminate()代表终止进程
import os
from multiprocessing import Process
from time import sleep
def task1(s,name):
while(True):
sleep(s)
# os.getpid();得到进程数字代号
# os.getppid():得到父进数字代号
print("这是任务一。。。。",os.getpid(),os.getppid(),name)
def task2(s,name):
while(True):
sleep(s)
# os.getpid();得到进数字代号
# os.getppid():得到父进数字代号
print("这是任务二。。。。",os.getpid(),os.getppid(),name)
if __name__ == '__main__':
print(os.getpid())
# target代表进程执行的函数,name代表进程的名字,args代表传递给函数的参数
p1 = Process(target=task1, name='进程一', args=(1, '张'))
p1.start()
p2 = Process(target=task2, name='进程二', args=(1, '李'))
p2.start()
自定义进程类必须继承于Process类,并且必须重写run()方法
如果自定义进程创建时,参数与Process创建时不同,要重写__ init() __方法
from multiprocessing import Process
class MyProcess(Process):
def __init__(self,name):
super(MyProcess, self).__init__()
self.name = name
# 重写run方法
def run(self):
n = 1
while True:
print('{}------>自定义进程,n:{}'.fromat(n,self.name))
n += 1
if __name__ == '__main__':
p1 = MyProcess("张三")
p1.start()
p2 = MyProcess("李四")
p2.start()
当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程
但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此时就可以用到multiprocessing模块提供的Pool方法。
初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来执行。
非阻塞模式:将所有进程添加按照进程池容量添加到进程池,在添加过程中每个进程也执行,若某一进程执行完毕,则自动跳出进程池,从队列中添加下一进程进行补位
#导入的包有:from multiprocessing import Pool;import time;import os;from random import random
def task(task_name):
print('开始做任务啦!',task_name)
start = time.time()
# 使用sleep
time.sleep(random() * 2)
end = time.time()
print('完成任务:{},用时:{},进程id:{}'.format(task_name,(end-start),os.getpid()))
#return '完成任务:{},用时:{},进程id:{}'.format(task_name,(end-start),os.getpid())
# 回调函数
# def callback_func(n):
# print(n)
if __name__ == '__main__':
# 定义进程池的容量为4
pool = Pool(5)
tasks = ['听音乐','玩游戏','吃饭','做饭','洗衣服','散步','看孩子']
for task1 in tasks:
# apply_async代表非阻塞模式
pool.apply_async(task,args=(task1,))
#参数callback是用来进行回调的,若task中有返回值,则可在定义一函数callback_func来接收处理返回值
#pool.apply_async(task,args=(task1,),callbakc=callback_func)
pool.close() #添加任务结束
pool.join() #让主进程让步,阻止主进程关闭,因为使用进程池时必须依赖主进程,主进程结束则进程池结束
print('over!!!')
"""
开始做任务啦! 听音乐
开始做任务啦! 玩游戏
开始做任务啦! 吃饭
开始做任务啦! 做饭
开始做任务啦! 洗衣服
完成任务:吃饭,用时:0.48550915718078613,进程id:7812
开始做任务啦! 散步
完成任务:散步,用时:0.09673190116882324,进程id:7812
开始做任务啦! 看孩子
完成任务:洗衣服,用时:0.5772693157196045,进程id:4320
完成任务:看孩子,用时:0.07913494110107422,进程id:7812
完成任务:听音乐,用时:1.3462684154510498,进程id:10352
完成任务:做饭,用时:1.5138163566589355,进程id:6776
完成任务:玩游戏,用时:1.9259545803070068,进程id:5368
over!!!
"""
阻塞模式:添加一个进程执行一个任务,该进程不结束另一进程就进不来进程池
from multiprocessing import Pool
import time
import os
from random import random
def task(task_name):
print('开始做任务啦!',task_name)
start = time.time()
time.sleep(random() * 2)
end = time.time()
print('完成任务:{},用时:{},进程id:{}'.format(task_name,(end-start),os.getpid()))
if __name__ == '__main__':
pool = Pool(5)
tasks = ['听音乐','玩游戏','吃饭','做饭','洗衣服','散步','看孩子']
for task1 in tasks:
# apply代表非阻塞模式
pool.apply(task,args=(task1,))
pool.close()
pool.join()
print('over!!!')
"""
开始做任务啦! 听音乐
完成任务:听音乐,用时:1.8785796165466309,进程id:3192
开始做任务啦! 玩游戏
完成任务:玩游戏,用时:0.4221527576446533,进程id:8992
开始做任务啦! 吃饭
完成任务:吃饭,用时:1.6727604866027832,进程id:7424
开始做任务啦! 做饭
完成任务:做饭,用时:0.305314302444458,进程id:2792
开始做任务啦! 洗衣服
完成任务:洗衣服,用时:0.8321800231933594,进程id:4516
开始做任务啦! 散步
完成任务:散步,用时:0.6783571243286133,进程id:3192
开始做任务啦! 看孩子
完成任务:看孩子,用时:0.18962836265563965,进程id:8992
over!!!
"""
进程间进行通信的方式之一是通过队列
from multiprocessing import Queue
q = Queue(4)
# 当队列满后,后面添加的元素只能等待除非有"空地",等待过程造成了阻塞
q.put('A')
q.put('B')
q.put('B')
q.put('D')
# 若想数据满后再添加不堵塞,使用参数timeout,设置等待时间后直接报异常
# q.put('E',timeout=3)
print(q.qsize())
# 获取队列值
print(q.get(timeout=3))
print(q.get(timeout=3))
print(q.get(timeout=3))
print(q.get(timeout=3))
q.put_nowait("E") # 添加元素不阻塞
q.get_nowait() # 得到元素不阻塞
from multiprocessing import Process, Queue
from time import sleep
def download(q):
images = ['girl.jpg', 'boy.jpg', 'man.jpg']
for image in images:
print('正在下载:', image)
sleep(0.5)
# 在下载过程中将图片保存在队列
q.put(image)
def getfile(q):
while True:
# 多次循环直至文件保存完毕
try:
file = q.get(timeout=5)
print("{}保存成功!".format(file))
except:
print('全部保存完毕!')
break
if __name__ == '__main__':
q = Queue(5)
# 将队列作为函数的参数传递
# 一个进程下载文件,一个进程保存文件
p1 = Process(target=download, args=(q,))
p2 = Process(target=getfile, args=(q,))
p1.start()
p2.start()
p2.join()
print("over!!!")
线程,有时被称为轻量进程,是程序执行流的最小单元。线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。
线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。
每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。
线程是程序中一个单一的顺序控制流程。进程内有一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指令运行时的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程
线程创建时需导入import threading,创建线程是使用类Thread进行,与进程创建方式类似
运行进程时用start()方法,代表启动进程并执行
from time import sleep
import threading
def download(n):
images = ['girl.jpg', 'boy.jpg', 'man.jpg']
for image in images:
print('正在下载:', image)
sleep(n)
print('{}下载完成'.format(image))
def eatfood():
foods = ['大碗宽面','炊饼','火锅','饺子']
for food in foods:
sleep(0.5)
print('正在吃{}'.format(food))
if __name__ == '__main__':
# 创建线程,与创建进程方式类似
t1 = threading.Thread(target=download,name='线程一',args=(1,))
t1.start()
t2 = threading.Thread(target=eatfood,name='线程二')
t2.start()
print('over!!!')
"""
正在下载: girl.jpg
over!!!
正在吃大碗宽面
正在吃炊饼
girl.jpg下载完成
正在下载: boy.jpg
正在吃火锅
boy.jpg下载完成
正在下载: man.jpg
正在吃饺子
man.jpg下载完成
"""
当多线程进行共享数据的使用时,Python底层会默认加锁解决线程的安全问题,但当计算量过大时,锁会自动消失,可能引发线程安全问题
所以多用进程来运行计算密集型程序,线程多用于耗时操作
在上述基础上,Python允许使用threading模块的Lock类可以实现简单的线程同步,这两个对象都有acquire方法和release方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到acquire和release方法之间。
import threading
ticket = 200
lock = threading.Lock()
def task1():
global ticket
# 获取线程锁,如果已经上锁,则等待释放
lock.acquire() #同时造成阻塞,没有锁就不运行
for i in range(100):
ticket -= 1
print('线程一:票数为',ticket)
lock.release() #释放锁
def task2():
global ticket
lock.acquire()
for i in range(100):
ticket -= 1
print('线程二:票数为',ticket)
lock.release()
if __name__ == '__main__':
t1 = threading.Thread(target=task1)
t2 = threading.Thread(target=task2)
t1.start()
t2.start()
t1.join()
t2.join()
print('over!!!')
死锁问题: