目录
- 基础知识
- 多进程
- 多进程间执行先后
- 进程通信(pipe queue)
- 多线程
- 线程安全
- GIL与Lock锁
- 线程进程总结
- 线程池
- 高并发拷贝(多进程,多线程)
说明
相应的学习视频见链接,本文只对重点进行总结。
B站视频-黑马程序,以及相应的黑马视频
课程同步的CSDN,写的细致
基础知识
多进程
重点(只要看下面代码的main函数即可)
- 创建
- 如何开守护进程
- 多进程,开销大,用for循环调用多个进程时,后台cpu一下就上去了
import time
import multiprocessing
import os
def dance(who,num):
print("dance父进程:{}".format(os.getppid()))
for i in range(1,num+1):
print("进行编号:{}————{}跳舞。。。{}".format(os.getpid(),who,i))
time.sleep(0.5)
def sing(num):
print("sing父进程:{}".format(os.getppid()))
for i in range(1,num+1):
print("进行编号:{}----唱歌。。。{}".format(os.getpid(),i))
time.sleep(0.5)
def work():
for i in range(10):
print("工作中。。。")
time.sleep(0.2)
if __name__ == '__main__':
# print("main主进程{}".format(os.getpid()))
start= time.time()
#1 进程的创建与启动
# # 1.1创建进程对象,注意dance不能加括号
# # dance_process = multiprocessing.Process(target=dance)#1.无参数
# dance_process=multiprocessing.Process(target=dance,args=("lin",3))#2.以args=元祖方式
# sing_process = multiprocessing.Process(target=sing,kwargs={"num":3})#3.以kwargs={}字典方式
# # 1.2启动进程
# dance_process.start()
# sing_process.start()
#2.默认-主进程和子进程是分开的,主进程只要1s就可以完成,子进程要2s,主进程会等所有子进程执行完,再退出
# 2.1子守护主进程,当主一但完成,子就断开(如qq一关闭,所有聊天窗口就没了).daemon=True
work_process = multiprocessing.Process(target=work,daemon=True)
work_process.start()
time.sleep(1)
print("主进程完成了!")#主进程和子进程是分开的,主进程只要1s就可以完成,子进程要2s,主进程会等所有子进程执行完,再退出
print("main主进程花费时长:",time.time()-start)
#
多进程间执行先后
- 默认情况下,主进程会等所有子进程执行完,再退出。
- 子进程设置成守护进程后,当主进程一旦完成,子进程立马结束
dance_process=multiprocessing.Process(target=dance,args=(“lin”,3),daemon=True) - 使用join()方法加塞,只有当设置的子进程结束后,才会开始主进程
sing_process.start()
dance_process.join()
print(“main主进程{}”.format(os.getpid()))
进程通信(pipe queue)
主要Queue和Pipe这两种方式,Queue用于多个进程间实现通信,Pipe是两个进程的通信
多线程
重点
- 创建
- 守护线程
- 线程安全问题(多人抢票,会抢到同一张)
import time
import os
import threading
def dance(num):
for i in range(num):
print("进程编号:{},线程编号:{}————跳舞。。。".format(os.getpid(),threading.current_thread()))
time.sleep(1)
def sing(count):
for i in range(count):
print("进程编号:{},线程编号:{}----唱歌。。。".format(os.getpid(),threading.current_thread()))
time.sleep(1)
def task():
time.sleep(1)
thread=threading.current_thread()
print(thread)
if __name__ == '__main__':
# start=time.time()
# # sing_thread =threading.Thread(target=dance,args=(3,),daemon=True)#设置成守护主线程
# sing_thread = threading.Thread(target=dance, args=(3,))
# dance_thread = threading.Thread(target=sing,kwargs={"count":3})
#
# sing_thread.start()
# dance_thread.start()
#
# time.sleep(1)
# print("进程编号:{}主线程结束...用时{}".format(os.getpid(),(time.time()-start)))
for i in range(10):#多线程之间执行是无序的,由cpu调度
sub_thread = threading.Thread(target=task)
sub_thread.start()
线程安全
B站链接
由于线程直接是无序进行的,且他们共享同一个进程的全部资源,所以会产生线程安全问题(比如多人在线抢票,买到同一张)
#下面代码在没有lock锁时,会卖出0票,加上lock就正常
import threading
import time
lock =threading.Lock()
class Sum_tickets:
def __init__(self,tickets):
self.tickets=tickets
def window(sum_tickets):
while True:
with lock:
if sum_tickets.tickets>0:
time.sleep(0.2)
print(threading.current_thread().name,"取票{}".format(sum_tickets.tickets))
sum_tickets.tickets-=1
else:
break
if __name__ == '__main__':
sum_tickets=Sum_tickets(10)
sub_thread1 = threading.Thread(name="窗口1",target=window,args=(sum_tickets,))
sub_thread2 = threading.Thread(name="窗口2",target=window,args=(sum_tickets,))
sub_thread1.start()
sub_thread2.start()
GIL与Lock锁
参考1
参考2
由于多线程是资源共享的,所以会带来线程安全问题,所以要加锁进行保护,保证同一时刻只能有一个线程来使用。
python提供两种锁,一个gil全局解释器锁,在多线程的过程中,比如垃圾回收线程,和普通线程会发生冲突,所以加了gil,保证同一时刻只有一个线程可以执行,正是由于这种机制,python下的多线程只能并发,并不是真正意义上的多线程。
第二个是lock锁,保证共享数据在某一时间内只能被一个线程修改,当该线程释放锁后,其他线程才能修改共享数据,让多线程变成了一种串行模式。
线程进程总结
- 线程是依附在进程里面的,没有进程就没有线程,一个进程可以创建多个线程
- 进程之间的资源相互独立,而同一进程下的线程共享资源。一个进程崩了,不会影响其他,而一个线程崩了产生阻塞,整个进程就没了。
- 进程是操作系统 资源分配的基本单位,比创建线程的资源开销要大,适用于cpu密集型工作(指大量的运算工作,比如上亿次浮点运算,占用大量cpu)
- 线程是 处理器调度的基本单位(程序执行的基本单位),资源开销小,适用于I/O密集型工作(web来回爬取网站信息,硬盘传输文件)
线程池
[参考视频]—线程池的使用(https://www.bilibili/video/BV1zy4y1M7xt?p=8&spm_id_from=pageDriver)
from concurrent.futures import ThreadPoolExecutor,as_completed,wait,FIRST_COMPLETED
#1.主线程可以获取某一个线程的状态,以及线程函数的返回值
#2.futures可以让多进程和多线程编码接口一致
import time
def get_html(t):
time.sleep(t)
print("get page {} success".format(t))
return t
# #1.样例的单个输入,submit提交执行函数,立即执行不会阻塞
# executor = ThreadPoolExecutor(max_workers=1)
# task1=executor.submit(get_html,(3))
# task2=executor.submit(get_html,(2))
# task2.cancel()
# print(task1.done())#查看线程是否完成,由于立即执行不会阻塞,所以状态False
# print(task1.result())#获取task执行结果
# print(task2.cancel())#False,当线程已经开始时,是无法cancel的,返回为false,当处于等待时进入pool时,是可取消的
#2.使用list,进行样例列表的输入
executor = ThreadPoolExecutor(max_workers=2)
urls=[3,2,4]
all_tasks=[executor.submit(get_html,(url)) for url in urls]
wait(all_tasks,return_when=FIRST_COMPLETED)#使用wait,阻塞主线程,这里设置当第一个线程执行完,才能进行主线程
print('main')
##法1:先完成的线程,先返回
for future in as_completed(all_tasks):#as_completed 将已完成的task找出来,已完成的顺序可以与输入顺序不同
data=future.result()
print("get {} page".format(data))
# ##2:按照输入的任务顺序,进行返回
# for data in executor.map(get_html,urls):#注意map返回的结果,就是上面future.result()
# print("get {} page".format(data))
高并发拷贝(多进程,多线程)
import os
import multiprocessing
import threading
import time
def copy_file(file_name,source_dir,dest_dir):
source_path = source_dir+"/"+file_name
dest_path =dest_dir+"/"+file_name
print("当前进程为:{}".format(os.getpid()))
with open(source_path,"rb") as source_file:
with open(dest_path,"wb") as dest_file:
while True:
data=source_file.read(1024)
if data:
dest_file.write(data)
else:
break
pass
if __name__ == '__main__':
source_dir=r'C:\Users\Administrator\Desktop\注意力'
dest_dir=r'C:\Users\Administrator\Desktop\test'
start = time.time()
try:
os.mkdir(dest_dir)
except:
print("目标文件已存在")
file_list =os.listdir(source_dir)
count=0
#1多进程
for file_name in file_list:
count+=1
print(count)
sub_processor=multiprocessing.Process(target=copy_file,
args=(file_name,source_dir,dest_dir))
sub_processor.start()
# time.sleep(20)
print(time.time()-start)
#这里有主进程和子进程,通过打印可以看出,主进程在创建1,2,3,4,,,21过程中,子进程已有的开始执行,也就是说,每个进程是互不影响的
# 9
# 10
# 11
# 12
# 13
# 当前进程为:2936(当主进程创建第13个时,此时,第一个子进程开始工作)
# 14
# 当前进程为:10120
# 当前进程为:10440
# 15
# 当前进程为:9508
# 2多线程
# for file_name in file_list:
# count += 1
# print(count)
# sub_thread = threading.Thread(target=copy_file,
# args=(file_name, source_dir, dest_dir))
# sub_thread.start()
# # time.sleep(20)
# print(time.time() - start)
更多推荐
python多进程、多线程、(并发\并行\串行)
发布评论