文章目录
- 一.进程
- 1.进程的概念
- 2.进程的特征
- 3. 单进程
- 4.多进程
- 5.加锁
- 6.pool方法
- 7.Queue(管道通信)
- 8.pipe(实现进程与进程之间通信)
- 9.生产者消费者模型
- 二.线程
- 1.线程的概念
- 2.单线程:一件事情一件事情地做
- 3.多线程(python中的多线程是伪多线程):同时做一件或多件事
- 4.守护主线程:
- 查看线程标识,ID
- join 可以对主线程进行阻塞,等所有的子线程运行结束在运行主线程
- 加锁
- 三.进程与线程的区别
一.进程
1.进程的概念
- 计算机的核心是CPU,承担了所有的计算任务
- 操作系统是计算机的管理者,负责任务的调度,资源的分配和管理,统领整个计算机硬件
- 应用程序是具有某种功能的程序,程序是运行于操作系统之上的
- 进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用程序运行的载体
- 进程是一种抽象的概念,从来没有统一的标准定义
- 进程一般由程序,数据集合和进程控制块三部分组成
- 程序用于描述进程要完成的功能,是控制进程执行的指令集
- 数据集合是程序在执行时所需要的数据和工作区
- 程序控制块包含进程的描述信息和控制信息是进程存在的唯一标志
2.进程的特征
- 独立性:进程是系统进行资源分配和调度的一个独立单位
- 结构性:进程由程序,数据和进程控制块三部分组成
- 动态性:进程是程序的一次执行过程,是临时的,有生命期的,是动态产生,动态消亡的
- 并发性:任何进程都可以同其他进行一起并发执行
3. 单进程
代码:
import time
import multiprocessing
def work_1(f,n):#f是修改的文件,n是几遍
print('work_1 start')
for i in range(n):
with open(f,'a') as fs:#a的方式打开文件
fs.write('i love pyhton \n')
time.sleep(1)#睡眠1秒
print('work_1 end')
def work_2(f,n):
print('work_2 start')
for i in range(n):
with open(f,'a') as fs:
fs.write('come on baby \n')
time.sleep(1)
print('work_2 end')
if __name__ == '__main__':
work_1('file.txt',3)#调用方法
work_2('file.txt',3)
结果:(在同级目录下创建file.txt并在里面写入内容)
work_1 start
work_1 end
work_2 start
work_2 end
4.多进程
代码:
import time
import multiprocessing
def work_1(f,n):
print('work_1 start')
for i in range(n):
with open(f,'a') as fs:
fs.write('i love pyhton \n')
time.sleep(1)
print('work_1 end')
def work_2(f,n):
print('work_2 start')
for i in range(n):
with open(f,'a') as fs:
fs.write('come on baby \n')
time.sleep(1)
print('work_2 end')
if __name__ == '__main__':
p1 = multiprocessing.Process(target=work_1,args = ('file.txt',3))
p2 = multiprocessing.Process(target=work_2, args=('file.txt', 3))
p1.start()
p2.start()
结果:
5.加锁
代码:
import time
import multiprocessing
#加锁
def work_1(f,n,lock):
print('work_1 start')
lock.acquire()
for i in range(n):
with open(f,'a') as fs:
fs.write('i love pyhton \n')
time.sleep(1)
print('work_1 end')
lock.release()
def work_2(f,n,lock):
print('work_2 start')
lock.acquire()
for i in range(n):
with open(f,'a') as fs:
fs.write('come on baby \n')
time.sleep(1)
print('work_2 end')
lock.release()
if __name__ == '__main__':
lock=multiprocessing.Lock()
p1 = multiprocessing.Process(target=work_1,args = ('file.txt',3,lock))
p2 = multiprocessing.Process(target=work_2, args=('file.txt', 3,lock))
p1.start()
p2.start()
结果:
#先写完进程1再写进程2
i love pyhton
i love pyhton
i love pyhton
come on baby
come on baby
come on baby
6.pool方法
代码1:
import os
import multiprocessing
import time
def work(n):
print('run work (%s) ,work id %s'%(n,os.getpid()))
time.sleep(5)
print('work (%s) stop ,work id %s'%(n,os.getpid()))
if __name__=='__main__':
print('Parent process %s.' % os.getpid())
#创建进程池
p = multiprocessing.Pool(3)
for i in range(5):
#创建5个进程,一次进入进程池
p.apply_async(work, args=(i,))
p.close()
p.join()
结果:
Parent process 30656.
run work (0) ,work id 29692
run work (1) ,work id 29304
run work (2) ,work id 29960 #一次只能执行3个进程,首先是0,1,2
work (0) stop ,work id 29692 #0执行完毕
run work (3) ,work id 29692 #3加入,此时执行的是1,2,3
work (1) stop ,work id 29304 #1执行完毕
run work (4) ,work id 29304 #4加入,此时执行的是1,2,3
work (2) stop ,work id 29960
work (3) stop ,work id 29692
work (4) stop ,work id 29304 #2,3,4执行完毕
进程已结束,退出代码 0
代码2:
import os
import multiprocessing
import time
def music(name,loop):
print(time.ctime())
for i in range(loop):
time.sleep(2)
print('您现在正在听的音乐是%s'%name)
def movie(name,loop):
print(time.ctime())
for i in range(loop):
time.sleep(2)
print('您现在正在看的电影是%s'%name)
if __name__=='__main__':
pool=multiprocessing.Pool(2)
pool.apply_async(func=music,args=('花太香',3))
pool.apply_async(func=movie,args=('王牌特工',4))
pool.apply_async(func=music, args=('爱的故事上集', 2))
pool.close()
# pool.terminate()
# 比较危险,不要轻易用,直接杀死进程池
#join阻塞主进程,当子进程执行完毕的时候会继续往后执行,使用join必须在进程池使用terminate或者close
pool.join()
print('结束时间是%s'%time.ctime())
结果:
Fri Jan 3 18:34:32 2020
Fri Jan 3 18:34:32 2020
您现在正在听的音乐是花太香
您现在正在看的电影是王牌特工
您现在正在听的音乐是花太香
您现在正在看的电影是王牌特工
您现在正在听的音乐是花太香
Fri Jan 3 18:34:38 2020
您现在正在看的电影是王牌特工
您现在正在听的音乐是爱的故事上集
您现在正在看的电影是王牌特工
您现在正在听的音乐是爱的故事上集
结束时间是Fri Jan 3 18:34:42 2020
进程已结束,退出代码 0
7.Queue(管道通信)
代码:
#-*- conding:utf-8 -*-
import multiprocessing
import time
#queue 跨进程通信
def put(q):
for value in ['A', 'B', 'C']:
print ('发送 %s 到 queue...' % value)
q.put(value) #通过put发送
time.sleep(2)
## 读数据进程执行的代码:
def get(q):
while True: #一直循环
value = q.get(True) #通过get接受队列中的数据
print ('从 queue 接受 %s .' % value)
if __name__=='__main__':
# 父进程创建Queue,并传给各个子进程:
q = multiprocessing.Queue()
pw = multiprocessing.Process(target=put, args=(q,))
pr = multiprocessing.Process(target=get, args=(q,))
# 启动子进程pw,写入:
pw.start()
# 启动子进程pr,读取:
pr.start()
# 等待pw结束:
pw.join()
# pr进程里是死循环,无法等待其结束,只能强行终止:
pr.terminate()
结果:
发送 A 到 queue...
从 queue 接受 A .
发送 B 到 queue...
从 queue 接受 B .
发送 C 到 queue...
从 queue 接受 C .
进程已结束,退出代码 0
8.pipe(实现进程与进程之间通信)
代码:
#-*- conding:utf-8 -*-
import multiprocessing
import time
#PIPE 管道通信
def put(p):
for value in ['A', 'B', 'C']:
print ('发送 %s 到 pipe...' % value)
p[1].send(value)#发送
time.sleep(2)
# 读数据进程执行的代码:
def get(p):
while True:
value = p[0].recv()#接收
print ('从 pipe 接受 %s .' % value)
if __name__=='__main__':
# 父进程创建Queue,并传给各个子进程:
# p = multiprocessing.Pipe()
p = multiprocessing.Pipe(duplex=False) #左收右发
pw = multiprocessing.Process(target=put, args=(p,))
pr = multiprocessing.Process(target=get, args=(p,))
# 启动子进程pw,写入:
pw.start()
# 启动子进程pr,读取:
pr.start()
# 等待pw结束:
pw.join()
# pr进程里是死循环,无法等待其结束,只能强行终止:
pr.terminate()
结果:
发送 A 到 pipe...
从 pipe 接受 A .
发送 B 到 pipe...
从 pipe 接受 B .
发送 C 到 pipe...
从 pipe 接受 C .
进程已结束,退出代码 0
9.生产者消费者模型
代码:
#-*- conding:utf-8 -*-
import threading
import time
import queue
q = queue.Queue(maxsize=10)
def producer(name): # 生产者
count = 1
while True:
q.put("辣条%s" % count)
print("渣女生产一包了辣条", count)
count += 1
time.sleep(0.5)
def consumer(name): # 消费者
while True:
print("[%s]取到[%s]并且吃了它..." % (name, q.get()))
time.sleep(1)
p = threading.Thread(target=producer, args=("丈母娘",))
c1 = threading.Thread(target=consumer, args=("渣男",))
c2 = threading.Thread(target=consumer, args=("老丈人",))
p.start()
c1.start()
c2.start()
结果:
渣女生产一包了辣条 1
[渣男]取到[辣条1]并且吃了它...
渣女生产一包了辣条 [老丈人]取到[辣条2]并且吃了它...2
渣女生产一包了辣条[渣男]取到[辣条3]并且吃了它...
3
渣女生产一包了辣条[老丈人]取到[辣条4]并且吃了它...
4
渣女生产一包了辣条[渣男]取到[辣条5]并且吃了它...
5
渣女生产一包了辣条[老丈人]取到[辣条6]并且吃了它...
6
渣女生产一包了辣条[渣男]取到[辣条7]并且吃了它...
7
渣女生产一包了辣条[老丈人]取到[辣条8]并且吃了它... 8
渣女生产一包了辣条[渣男]取到[辣条9]并且吃了它...
9
........
CTRL+C退出,否则会一直执行
二.线程
1.线程的概念
- 早期的操作系统中没有线程的概念,进程是拥有资源和独立运行的最小单位,也是程序执行的最小单位
- 任务调度采用的是时间片轮转的抢占式调度方式
- 进程是任务调度的最小单位,每个进程有各自独立的一块内存,使得各个进程之间内存地址相互隔离
- 随着计算机的发展,对CPU的要求越来越高,进程之间的切换开销较大,已经无法满足越来越复杂的程序的要求了。于是就发明了线程,线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位
- 一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间)
- 一个标准的线程由线程ID,当前指令指针PC,寄存器和堆栈组成。进程由内存空间(代码,数据,进程空间,打开的文件)和一个或多个线程组成
2.单线程:一件事情一件事情地做
- 当处理器需要处理多个任务时,必须对这些任务安排执行顺序,并按照这个顺序来执行任务。假如我们创建了两个任务:听音乐(music)和看电影(movie)。在单线程中,我们只能按先后顺序来执行这两个任务
threading.Thread(self, group=None, target=None, name=None, args=(), kwargs={})
参数group是预留的,用于将来扩展
参数target是一个可调用对象(也称为活动[activity]),在线程启动后执行
参数name是线程的名字。默认值为“Thread-N“,N是一个数字
参数args和kwargs分别表示调用target时的参数列表和关键字参数
- 代码:
import time
import threading
def music(name,loop):
for i in range(loop):
print('listen music %s %s'%(name,time.ctime()))
time.sleep(1)
def movie(name,loop):
for i in range(loop):
print('look movie %s %s'%(name,time.ctime()))
time.sleep(1)
if __name__ == '__main__':
music('爱的故事上集',3)
movie('晓生克的救赎',4)
print('end time %s'%time.ctime())
结果:
listen music 爱的故事上集 Fri Jan 3 17:50:56 2020
listen music 爱的故事上集 Fri Jan 3 17:50:57 2020
listen music 爱的故事上集 Fri Jan 3 17:50:58 2020
look movie 晓生克的救赎 Fri Jan 3 17:50:59 2020
look movie 晓生克的救赎 Fri Jan 3 17:51:00 2020
look movie 晓生克的救赎 Fri Jan 3 17:51:01 2020
look movie 晓生克的救赎 Fri Jan 3 17:51:02 2020
end time Fri Jan 3 17:51:03 2020
进程已结束,退出代码 0
3.多线程(python中的多线程是伪多线程):同时做一件或多件事
代码:
import time
import threading
def music(name,loop):
for i in range(loop):
print('listen music %s %s %s'%(name,time.ctime(),threading.Thread.getName(t1)))#输出线程名字
time.sleep(1)
def movie(name,loop):
for i in range(loop):
print('look movie %s %s %s'%(name,time.ctime(),threading.Thread.getName(t2)))
time.sleep(1)
#创建多线程
t1 = threading.Thread(target= music,args=('爱的故事上集',4))
t2 = threading.Thread(target= movie,args=('肖生克的救赎',4),name = 'movieThread')#设置线程名字
t1.setName('musicThread')#设置线程名字
if __name__ == '__main__':
# 启动线程
t1.start()
t2.start()
print('end time %s'%time.ctime())
4.守护主线程:
代码:
#守护主线程,主线程结束杀死子线程
t1.setDaemon(True)
t2.setDaemon(True)
查看线程标识,ID
代码:
print(t1.ident)
print(t2.ident)
join 可以对主线程进行阻塞,等所有的子线程运行结束在运行主线程
代码:
t1.join()
t2.join()
加锁
代码:
import time
import threading
balance = 0#定义一个变量
def change(n):
global balance
balance+=n
balance-=n
lock = threading.Lock() #获取线程锁
def run_thread(n):
for i in range(1000000):
lock.acquire() #获取锁
try:
change(n)
finally:
lock.release()#释放锁
t1 = threading.Thread(target= run_thread,args=(4,))#创建线程
t2 = threading.Thread(target= run_thread,args=(8,))
t1.start()
t2.start()# 启动线程
t1.join()#对主线程进行阻塞
t2.join()
print(balance)
三.进程与线程的区别
- 线程是程序执行的最小单位,而进程是操作系统分配资源的最小单位
- 一个进程由一个或多个线程组成,线程是一个进程中代码的不同执行路线
- 进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段,数据集,堆等)及一些进程级的资源(如打开文件和信号等),某进程内的线程在其他进程不可见
- 调度和切换:线程上下文切换比进程上下文切换要快得多