- 简单的概念术语
- 并发
- 并行
- 单进程
- 多进程
- 单线程 / 多线程
- multiprocessing模块-———基于进程的并行
- (1)multiprocessing.Process—参数args(,)kwarg{}—语法
- (2)获取进程的编号
- (3) 守护进程:
- Threading模块——
- (1) threading——常用参数
- (2)join()————子线程终止的使用。
- (3)Lock()——子线程锁的运用。
单核 多个任务交替进行完成;
简单理解:
一个人(相当于一个核)做饭 ,你得买菜,煮饭,切菜,炒菜 。
一个人完成整个做饭的过程。
就是为了执行完成多个任务。
多个CPU同时执行任务完成;
简单理解:
做饭的时候有多个人来帮你一起,有人洗菜,有人煮饭,有人切菜,有人炒菜;提高做饭的效率
多个CPU同时协助执行提高效率。
进程的概念:一个正在打开运行中的程序就称为进程,
通俗理解就相当于QQ,微信运行起来的程序
打开后就变成了一个各自独立的进程,任务管理器中可查看,
一个运行起来的程序至少有一个进程。
多个运行起来的程序就是一个多进程;
简单理解 :
在家想做饭吃牛肉和螃蟹,为了提高效率叫表弟去买螃蟹,表妹去买虾,自己则在家里煮饭,来提高想吃饭的效率。
多任务同时执行充分调用CPU资源来提高效率。
主进程和子进程同时执行。
线程是程序执行的最小单位,线程是依附于进程中执行的,一个程序默认最少都会有一个线程。
简单理解:
你有一个想接满水的大盆,(线程好比水龙头)你开一个水龙头接水,和开多个水龙头接水,效率远远不一样。
就像打开QQ 后想和多个人聊天,打开多个聊天窗口(多个线程)的聊天一样,实现多任务的同时节省了资源。
进程的创建步骤
(1)导入进程包
#先导入包 import multiprocessing
(2)通过进程类创建进程对象
进程对象 = multiprocessing.Process()
(3)启动进程执行任务
进程对象.start()
通过进程类创建进程对象
进程对象 =multiprocessing.Process(target=任务名)
任务名就是接下来的函数名 注意的是任务名不要(),不然就是调用,这里是为了多进程的索引。
| 参数名 | 说明 |
|---|---|
| target | 执行目标的名 |
| name | 进程名,默认系统设置,可手动指定 |
| group | 进程组,目前None |
# 唱歌
def sing():
for i in range(3):
print('小明', end='')
print('唱歌----')
time.sleep(0.5)
# 跳舞
def dance():
for i in range(3):
print('小花', end='')
print('跳舞----')
time.sleep(0.5)
if __name__ == '__main__':
start_time= time.time() #计时
dance()
sing()
end_time = time.time()
all_time = end_time-start_time
print(f'时间:{all_time}')
——可以看到函数的调用就是单个执行——总时间
想在快点 执行完成 。
我们再更改一下唱跳一起执行:
if __name__ == '__main__':
start_time= time.time() #开始计时
dance_process = multiprocessing.Process(target=dance,)
sing_process = multiprocessing.Process(target=sing)
dance_process.start() #启动子进程
sing_process.start()
end_time = time.time()
all_time = end_time-start_time
print(f'时间:{all_time}')
——从时间上看快了不止快了 ‘‘亿’’ 点点——
arg(,)元组传递中间得有逗号以保证是一个元组
元组传递参数是按照 位置传参,不然报错
kwargs{}是字典传参
按照关键字传参,传入的参数名和函数接受的名字得一样 否则报错
#跳舞
def dance(num,name): #kwargs()关键字传参
for i in range(num):
print(name, end='')
print('跳舞----')
time.sleep(0.5)
#唱歌
def sing(num,name): #arg(,)元组参数
for i in range(num):
print(name, end='')
print('唱歌----')
time.sleep(0.3)
if __name__ == '__main__':
start_time= time.time()
sing_process = multiprocessing.Process(target=sing, args=(10, '小明'))
dance_process = multiprocessing.Process(target=dance, kwargs={'num': 5, 'name': '小花'})
dance_process.start()
sing_process.start()
end_time = time.time()
all_time = end_time-start_time
print(f'时间:{all_time}')
(2)获取进程的编号
1.获取当前进程的编号 os.getpid() 2.获取当前父进程的编号() os.getppid() 注意两个pp
# 跳舞
def dance(num, name):
print('跳舞进程--pid:', os.getpid(),
'n跳舞进程的父进程:', os.getppid())
for i in range(num):
print(name, end='')
print('跳舞----')
time.sleep(0.5)
# 跳舞
def dance(num, name):
print('跳舞进程--pid:', os.getpid(),
'n跳舞进程的父进程:', os.getppid())
for i in range(num):
print(name, end='')
print('跳舞----')
time.sleep(0.5)
if __name__ == '__main__':
print('主进程的pid:', os.getpid())
start_time= time.time()
sing_process = multiprocessing.Process(target=sing, args=(10, '小明'))
dance_process = multiprocessing.Process(target=dance, kwargs={'num': 5, 'name': '小花'})
dance_process.start()
sing_process.start()
end_time = time.time()
all_time = end_time-start_time
print(f'时间:{all_time}')
———可查看到当前运行的进程编号,和父亲进程的编号————
多进程的编号注意点:
多进程的特点就是主进程——会等待所有的 子进程结束后才结束。
简单解释:打开QQ,找两个好友聊天,(两个好友的对话框就是两个子进程),并不是关闭QQ等待两个对话框关闭后QQ才关闭,
我们实际需求是关闭QQ程序,两个对话框会自动关闭。
——举个代码
def work():
for i in range(10):
print('----工作中---')
time.sleep(0.2)
if __name__ =='__main__':
#创建子进程:
work_process = multiprocessing.Process(target=work)
work_process.start()
time.sleep(1)
print('————主进程执行完成————')
——从图可知
主进程并不会结束后自动关闭 而是要等待 子进程结束后才关闭。
但是我们需求是:主程序关闭——子进程就关闭,
所以就有一个概念:守护主进程
他的作用就是为了实现主程序关闭 而关闭。
设置守护进程 子进程守护主进程,当主进程关闭 子进程将不再运行
进程名.daemon = True
主进程会默认等待子进程执行结束再结束进程
如果是想让主进程结束子进程同样结束时 设置守护主进程就好 。
———需要注意的是:
进程名.daemon = True 代码要在子进程执行前。
| 参数 | 说明 |
|---|---|
| threading.active_count() | 现在运行的线程数量 |
| threading.enumrate() | 显示现在运行的是哪个线程 |
| threading.current_thread() | 正在运行的线程名 |
import threading
def main():
print(threading.active_count())
print(threading.enumerate())
print(threading.current_thread())
if __name__ =='__main__':
main()
threading.Tread(target=定义的线程函数名没有括号 只是为了方便索引,name =起的线程名字,args=传入线程名的参数) 和进程差不多。
线程名.start() 让线程的开始
线程名.join() 让线程的停止
值得注意的是:
(2)join()————子线程终止的使用。''' 多线程运行 并不是等待子线程运行完了以后 才开始运行主线程,而是和子线程 ---同时运行-- 但是有时为了子线程全部运行完了,才开始运行主线程后面的程序。 所以就需要 join() 语法规则 ————线程名.join() '''
代码演示:
import threading
import time
def T1_job():
print('T1 start')
for i in range(10):
time.sleep(0.1)
print('T1--finish--')
def T2_job():
print('T2 start')
print('T2--finish--n')
def main():
T1_thread = threading.Thread(target=T1_job, name='T1')
T2_thread = threading.Thread(target=T2_job, name='T2')
T1_thread.start()
T2_thread.start()
# T1_thread.join()
# T2_thread.join()
print('all--done--')
if __name__ == '__main__':
main()
结果显示————并没有等待子线程 T1 ,T2运行完才开始运行。而是同时进行的。
所以为了 所有的子线程运行完了
以后才开始运行主线程后面的 程序加上注释的 join()
结果显示————
——子线程和子线程之间运行的顺序是 无序的
import threading
def T1_job():
global A,lock
#lock.acquire()
for i in range(10):
A += 1
print('T1-job', A)
#lock.release()
def T2_job():
global A,lock
#lock.acquire()
for i in range(10):
A += 10
print('T2-job', A)
#lock.release()
if __name__ == '__main__':
A = 0
#lock = threading.Lock()
T1_thread = threading.Thread(target=T1_job, name='T1')
T2_thread = threading.Thread(target=T2_job, name='T2')
T1_thread.start()
T2_thread.start()
T1_thread.join()
T2_thread.join()
——定义两个线程 T1是每次加1,T2是每次加10
————可以看到运行的结果 :子进程之间并不是有序的运行。
没乱多运行七八次就可以 看到效果。
为了保证各个子线程运行中不被其他的子线程所打扰 就有一个lock
所以就调用treading中的Lock 锁住进程
lock = threading.Lock() lock.acquire() 先得到 ——代码块———— lock.release() 然后解锁**
取消上图的注释代码——可以看到 子线程之间是运行时互不打扰的。
_
_
_
_
_
_
——————如有错误不足之处指出 ,望各位及时指正————



