进程:
进程就是一组资源的集合
线程是在进程里面干活的
一个进程里面至少有一个线程,这个线程就是主线程
电脑CPU是几核的就只能同时运行几个任务(线程)
python里面的多线程其实只能用一个核
GIL 全局解释器锁
锁:多线程同时操作同一数据时必须加锁
CPU密集型任务 (CPU干活) -----多进程
IO密集型任务(磁盘IO、网络IO)-----多线程
启动多线程、主线程等待子线程结束
#进程就是一组资源的集合
# 线程是在进程里面具体干活的
import threading
import time
def run():
time.sleep(5)
print('over')
start_time = time.time()
for i in range(20): #需要多少个线程循环多少次
t = threading.Thread(target=run) #实例化一个线程
t.start() #启动这个线程
print('运行的时候有几个活跃线程',threading.activeCount()) #21 threading.activeCount() 当前有多少个线程在活跃
# while循环--主线程等待子线程运行结束
while threading.activeCount() !=1: #当所有的子进程都结束时,只剩一个主线程
pass
print('现在几个活跃线程',threading.activeCount()) #1
ent_time = time.time()
print(ent_time-start_time)
# for循环--主线程等待子线程运行结束
'''
start_time = time.time()
ths = []
for i in range(20): #需要多少个线程循环多少次
t = threading.Thread(target=run) #实例化一个线程
t.start() #启动这个线程
# t.join() #在这里加join,线程就变成串行的了
ths.append(t) #建一个list,把每个已启动的线程存起来
for thread in ths:
thread.join() #循环等待每个线程结束
ent_time = time.time()
print(ent_time-start_time) #5.004632949829102
'''
继承Thread类的方法启动多线程
import threading
import time
class MyThread(threading.Thread): #继承Tread类
def run(self): #这个方法必须叫run 重写父类run方法
time.sleep(5)
print('run')
for i in range(5):
t = MyThread() #实例化一个线程
t.start() #start()方法启动线程
获取多线程的返回值
import requests
import threading
all_res = [] #定义一个list,保存所有的返回结果
def get_name(name):
r = requests.get('http://api.nnzhp.cn/api/user/stu_info?stu_name=%E5%B0%8F%E9%BB%91',
params=name)
res = r.json()
all_res.append(res) #将这次请求的返回结果保存到 all_res中
for i in range(10):
t = threading.Thread(target=get_name,args=(i,))
t.start()
while threading.activeCount()!= 1:
pass
print(all_res)
守护线程
#主线程 : 秦始皇
#守护线程:秦始皇修护陵墓的人
import threading
import time
def hhh():
time.sleep(5)
print('hhh')
for i in range(100):
t = threading.Thread(target=hhh)
t.setDaemon(True) #设置子线程为守护线程 主线程死的时候,守护线程也得死
t.start()
print('秦始皇死了')
锁
import threading
num = 0 #全局变量
lock =threading.Lock() #申请一把锁 多线程同时操作同一个数据的时候一定要加锁
def xiaojun():
global num #想要修改全局变量,先声明它是global类型
# lock.acquire() #加锁
# num += 1
# lock.release() #解锁 只加锁不解锁会导致死锁
with lock: #with自动管理上下文 不需自己手动加锁/解锁
num+=1
for i in range(100):
t = threading.Thread(target=xiaojun)
t.start()
while threading.activeCount()!=1:
pass
print(num)
多进程
from multiprocessing import Process
import time
import threading
'''启动10个进程,每个进程启动10个线程'''
def run_thread():
time.sleep(60)
print('%s在运行'%threading.current_thread()) #threading.current_thread() 当前线程名
def run():
for i in range(10):
t = threading.Thread(target=run_thread)
t.start()
if __name__ =='__main__':
for i in range(10):
p = Process(target=run) #实例化一个进程
p.start() #启动进程
print(p.pid) #打印进程号
队列- Queue
Queue是python标准库中的线程安全的队列(FIFO)实现,提供了一个适用于多线程编程的先进先出的数据结构,即队列,用来在生产者和消费者线程之间的信息传递
join()
阻塞调用线程,直到队列中的所有任务被处理掉。
只要有数据被加入队列,未完成的任务数就会增加。当消费者线程调用task_done()(意味着有消费者取得任务并完成任务),未完成的任务数就会减少。当未完成的任务数降到0,join()解除阻塞。
put(item[, block[, timeout]])
将item放入队列中。
- 如果可选的参数block为True且timeout为空对象(默认的情况,阻塞调用,无超时)。
- 如果timeout是个正整数,阻塞调用进程最多timeout秒,如果一直无空空间可用,抛出Full异常(带超时的阻塞调用)。
- 如果block为False,如果有空闲空间可用将数据放入队列,否则立即抛出Full异常
其非阻塞版本为put_nowait
等同于put(item, False)
get([block[, timeout]])
从队列中移除并返回一个数据。block跟timeout参数同put
方法
其非阻塞方法为`get_nowait()`相当与get(False)
empty()
如果队列为空,返回True,反之返回False
from multiprocessing import Process,Queue
import os, time, random
#写数据进程执行的代码
def write(q):
for value in ['A','B','C']:
print('Put %s to queue...'%value)
q.put(value)
time.sleep(random.random())
#读数据进程执行的代码
def read(q):
while True:
if not q.empty():
value = q.get(True)
print('Get %s from queue.'%value)
time.sleep(random.random())
else:
break
if __name__ == '__main__':
#父进程创建Queue,并传给各个子进程
q = Queue()
pw =Process(target=write,args=(q,))
pr = Process(target=read,args=(q,))
#启动子进程pw,写入
pw.start()
#等待pw结束
pw.join()
#启动子进程pr,读取:
pr.start()
pr.join()
#pr进程里是死循环,无法等待其结束,只能强行终止
print('')
print('所有数据都写入并且读完')