一、进程
(一)什么是进程
当我们双击时,操作系统将程序装载到内存中,操作系统为它分配资源,然后才能运行。运行起来的程序就称之为进程。
程序和进程的对应关系是:程序只有一个,但可执行多次;进程可以有多个。
进程是资源分配的最小单位。
(二)创建进程
1.单进程
import time
def sing():
for i in range(3):
print('我在唱第{}句歌词'.format(i+1))
time.sleep(1)
def dance():
for i in range(3):
print('我在跳第{}段舞蹈'.format(i+1))
time.sleep(1)
if __name__ == '__main__':
sing()
dance()
2.多进程
from multiprocessing import Process
import time
def sing():
for i in range(3):
print('我在唱第{}句歌词'.format(i+1))
time.sleep(1)
def dance():
for i in range(3):
print('我在跳第{}段舞蹈'.format(i+1))
time.sleep(1)
if __name__ == '__main__':
t1=Process(target=sing)
t2=Process(target=dance)
t1.start()
t2.start()
多进程时,每个进程需要一份系统资源,资源不共享,两个进程互不干扰。
from multiprocessing import Process
count=0
def hs1():
global count
for i in range(1000):
count+=1
print('函数1:',count)
def hs2():
global count
for i in range(1000):
count+=1
print('函数2:',count)
if __name__ == '__main__':
p1=Process(target=hs1)
p2=Process(target=hs2)
p1.start()
p2.start()
父子进程的ID,传参:
from multiprocessing import Process
import os
def sing(num):
print('参数:',num,'进程的ID:',os.getpid(),'父进程ID:',os.getppid())
def dance(num):
print('参数:',num,'进程的ID:',os.getpid(),'父进程ID:',os.getppid())
if __name__ == '__main__':
print('主进程ID:',os.getpid())
p1=Process(target=sing,args=(9,))
p2=Process(target=dance,args=(99,))
p1.start()
p2.start()
(三)进程的状态
1.就绪状态
当进程已经分配到出CPU以外的所有必要的资源,只要获得处理机便可立即执行。
2.执行状态
当进程已获得处理机,其程序正在处理机上执行。
3.阻塞状态
正在执行的进程,由于等待某个时间发生而无法执行时,便放弃处理机而处于阻塞状态。
(四)队列--一种先进先出的线性数据结构
put()--向队列中存放数据,若已满,此方法将阻塞至有空间可用为止。
get()--返回队列中的一个项目,若列表为空,此方法将阻塞,直至队列中有项目可用为止。
qsize()--获取队列中的数据数量
full()--判断队列是否已满
empty()--判断队列是否已空
from multiprocessing import Queue
q=Queue(4) # 4--队列容量,若超出,程序阻塞
q.put('包子')
q.put('香蕉')
q.put('西瓜')
print(q.full())
while q.qsize()>0:
print(q.get())
print(q.empty())
block=False--不等待,直接抛出异常
from multiprocessing import Queue
q=Queue(3)
q.put(10)
q.put(20)
q.put(30)
try:
q.put(40,block=False) # 不等待,直接抛出异常
except:
print('队列已满,无法再存放数据')
print('结束')
from multiprocessing import Queue
a=Queue(3)
a.put(10)
a.put(20)
a.get()
a.get()
try:
a.get(block=False)
except:
print('队列已空,取不出东西了')
print('结束')
(五)进程之间的通信(需要借助队列)
from multiprocessing import Queue,Process
import time
def producer(q):
for i in range(10):
bz='包子:%d'%(i+1)
print('生产'+bz)
q.put(bz)
time.sleep(1)
def consumer(q):
for i in range(10):
bz=q.get()
print('消费'+bz)
if __name__ == '__main__':
q=Queue(3)
p1=Process(target=producer,args=(q,))
p2=Process(target=consumer,args=(q,))
p1.start()
p2.start()
(六)进程子类化
from multiprocessing import Queue,Process
import os,time
class SubProcess(Process):
def __init__(self,x):
super().__init__()
self.x=x
# 重新编写run函数,覆盖父类的run方法。进程启动时调用此方法
def run(self):
for i in range(self.x):
print('启动进程',i,os.getpid())
time.sleep(1)
if __name__ == '__main__':
p=SubProcess(3)
# 不同于直接调用run函数,这里是启动进程
p.start()
p1=SubProcess(3)
p1.start()
(七)进程池
1.阻塞式--同一时刻只跑一个进程
from multiprocessing import Pool
import time
def hs(name):
for i in range(5):
print(name,i)
time.sleep(1)
if __name__ == '__main__':
p=Pool(3)
a='abcde'
for x in a:
p.apply(hs,(x,)) # 阻塞式,同时只跑一个进程
p.close()
2.非阻塞式--同一时刻可跑多个进程,最多要看进程池的容量
from multiprocessing import Pool
import time
def hs(name):
for i in range(5):
print(name,i)
time.sleep(1)
if __name__ == '__main__':
p=Pool(3)
a='abcde'
for x in a:
# 非阻塞式,同时可跑多个进程,最多要看进程池的容量。
# 必须加join(),在close()后加
p.apply_async(hs,(x,))
p.close()
p.join() # 阻塞主进程,等待子进程结束
非阻塞式应用
1.通信
from multiprocessing import Pool
import time
def zuoye(name):
print(name+'在写代码')
time.sleep(1)
return name+'写完代码了'
def wan(status):
print('出去玩,'+status)
if __name__ == '__main__':
p=Pool(1)
# callback--回调
p.apply_async(zuoye,('张三',),callback=wan)
p.close()
p.join()
2.模拟下载器原理
from multiprocessing import Pool
import time
def downLoad(movie):
for i in range(5):
print(movie,'下载进度%.2f%%'%((i+1)/5*100))
time.sleep(1)
return movie
def alert(name):
print(name,'下载完毕,请收看')
if __name__ == '__main__':
movies=['哪吒','金刚葫芦娃','黑猫警长','小青龙','亚洲飞鹰','A计划']
p=Pool(4)
for movie in movies:
p.apply_async(downLoad,args=(movie,),callback=alert)
p.close()
p.join()
二、线程
(一)概念
进程是资源拥有者,创建、撤销与切换存在较大的内存开销,因此需要引入轻型进程,即线程。
线程是CPU调度的最小单位(程序真正执行的时候调用的是线程)。
(二)进程和线程之间的关系
每一个进程中至少有一个线程。
进程中的所有线程共享进程中的所有资源。
(三)使用threading模块创建线程
from threading import Thread
count=0
def hanshu1():
global count
for i in range(100):
count+=1
print('函数1',count)
def hanshu2():
global count
for i in range(100):
count+=1
print('函数2',count)
if __name__ == '__main__':
t1=Thread(target=hanshu1)
t2=Thread(target=hanshu2)
t1.start()
t2.start()
from threading import Thread
import time
import os
def sing():
for i in range(10):
print('唱歌%d'%(i+1))
time.sleep(1)
print(os.getpid())
def dance():
for i in range(10):
print('跳舞%d'%(i+1))
time.sleep(1)
print(os.getpid())
if __name__ == '__main__':
t1=Thread(target=sing)
t2=Thread(target=dance)
t1.start()
t2.start()
1.setDaemon()--将当前线程设置为守护线程来守护主线程
from threading import Thread
import time
def get(num):
for i in range(num):
print(i)
time.sleep(1)
if __name__ == '__main__':
t1=Thread(target=get,args=(5,))
# 需要在子线程开启之前设置
# 当主线程结束时,守护线程也就结束,不管是否执行完成
t1.setDaemon(True)
t1.start()
print('主线程结束了')
2.join()方法--当前线程执行完后其他线程才会继续执行。
3.threading模块提供的方法
threading.currentThread()--返回当前的线程变量。
threading.enumerate()--返回一个包含正在运行的线程的列表。
threading.active_count()或threading.activeCount()--返回正在运行的线程的个数。与len(threading.enumerate())有相同的结果。
from threading import Thread
import threading
import time
def sing():
for i in range(10):
print('唱歌%d'%(i+1),threading.current_thread())
time.sleep(2)
def dance():
for i in range(10):
print('跳舞%d'%(i+1),threading.current_thread())
time.sleep(1.5)
if __name__ == '__main__':
t1=Thread(target=sing,name='刘德华')
t2=Thread(target=dance,name='张惠妹')
t1.start()
t2.start()
print(threading.enumerate())
print(threading.activeCount())
t1.join()
t2.join()
print('主线程结束')
(四)线程子类化
import time,os
from threading import Thread
class T(Thread):
def __init__(self,name):
super().__init__()
self.name=name
def run(self):
for i in range(10):
print(self.name,'跳舞%d'%(i+1))
time.sleep(1)
print(os.getpid())
class C(Thread):
def __init__(self,name):
super().__init__()
self.name=name
def run(self):
for i in range(10):
print(self.name, '唱歌%d' % (i + 1))
time.sleep(1)
print(os.getpid())
if __name__ == '__main__':
t=T('张三')
c=C('张三')
t.start()
c.start()
(五)共享全局变量
import threading
g_num=10
def hanshu1():
global g_num
g_num+=5
def hanshu2():
print(g_num)
if __name__ == '__main__':
t1=threading.Thread(target=hanshu1)
t2=threading.Thread(target=hanshu2)
t1.start()
t2.start()