# 特别简单
# 进程
# 操作系统发展
# 没有操作系统 —— 穿孔卡片
# 批处理系统 —— 串行 ,速度块
# 联机批处理 读磁带的时候速度快
# 脱机批处理 读磁带和cpu工作并发
# 多道程序系统 —— 并行
# 操作系统的各种管理功能
# 时空的复用 : 空间隔离开来,cpu看起来可以处理多个任务
# 分时系统 —— 更好的实现了 并行
# 让cpu的工作效率下降了
# 实时系统 —— 对一个任务实时响应
# 优点 快
# 缺点 能处理的任务更少
# 通用操作系统
# 兼具多个操作系统的特性
# 操作系统的功能
# 封装了对硬件的操作过程,给应用程序提供好用的接口
# 对多个作业进行调度管理来分配硬件资源
# 进程
# 程序
# 只有在运行当中的程序 —— 进程
# 操作系统和进程的关系
# 为什么要引入进程的概念
# 隔离资源
# 进程是操作系统中资源分配的最小单位
# 进程是怎么被调度的呢?
# 先来先服务算法 FCFS
# 短作业优先算法
# 时间片轮转算法
# 多级反馈算法
# 进程Process
# 1 = [p2,p3,p4,p5,p7]
# 2 = [p1,p2,p3]
# 3 = [p6]
# 现代的操作系统中
# 进程
# 异步 只管调度 不等结果
# 同步 调度之后 还一定要等到结果
# 异步 我拿一个号
# 同步
# 阻塞
# 非阻塞
# —— 影响进程的调度
# 进程的状态 : 就绪 运行 阻塞
# 进程的创建与结束
# 创建进程有很多方式 —— 就是让一个程序运行起来
# 所有的进程都是被进程创建出来的
# 父进程 子进程
# 进程的结束
Python进程代码示例如下:
# import os
# import time
# print(os.getpid()) # 获取当前运行的python程序的进程id process id
# print(os.getppid()) # parent process id 获取当前进程的父id
# time.sleep(100)
# python当中创建进程来替我做事情
# multiprocess模块
# 综合的 处理进程的 包
# multi 多元的综合
# process 进程
# Process 和创建进程相关
# import os
# import time
# from multiprocessing import Process
# # def func(money):
# # time.sleep(3)
# # print('取钱 :%d'%money)
#
# # if __name__ == '__main__':
# # p = Process(target=func,args=(1,)) # 创建一个进程对象
# # p.start() # 直到执行start才有了进程
# # print('去取钱')
# # p.join() # 阻塞
# # print('取完钱了')
# # 在同一个进程中 程序确实是从上到下依次进行
# # 阻塞 程序又阻塞了
#
# # 创建进程对象 传要执行的函数 以及参数
# # 进程对象.start()
# # 主进程和子进程就是异步执行
# # 如果主进程中的代码已经结束了,子进程还没结束,主进程会等待子进程
#
# # p.join 就是主进程会阻塞在join的位置,等待p进程结束
# # windows操作系统中 创建进程的语句一定要放在if __name__ == '__main__':条件语句下面
#
# # 开启多个子进程
# # import os
# # import time
# # from multiprocessing import Process
# # def func(i):
# # time.sleep(1)
# # print('%d :子进程%d干的事儿,父进程:%d'%(i,os.getpid(),os.getppid()))
# #
# # if __name__ == '__main__':
# # # 100
# # p_lst = []
# # for i in range(10):
# # p = Process(target=func,args=(i,))
# # p.start()
# # p_lst.append(p)
# # for p in p_lst:p.join()
# # print('------主进程------')
#
# # 另一种开启进程的方式
# # 通过继承
# # import os
# # from multiprocessing import Process
# # class MyProcess(Process):
# # def run(self):
# # print('子进程:%d'%os.getpid())
# # self.walk() # --->在子进程中调用
# #
# # def walk(self): # 自定义的 可以不定义
# # print('子进程:%d' % os.getpid())
# #
# # if __name__ == '__main__':
# # p = MyProcess()
# # p.start() # ---> run方法
# # # p.walk() # ---> 在主进程中调用
# # print('主进程 :',os.getpid())
#
# # 必须创建一个类 必须继承Process类
# # 必须实现一个run方法
#
# # 调用阶段
# # 先实例化一个对象
# # 对象.start()
#
#
# import os
# from multiprocessing import Process
# # class MyProcess(Process):
# # def __init__(self,arg1,arg2):
# # super().__init__()
# # self.arg1 = arg1
# # self.arg2 = arg2
# #
# # def run(self):
# # print('子进程:%d,%s,%s'%(os.getpid(),self.arg1,self.arg2))
# # self.walk() # --->在子进程中调用
# #
# # def walk(self): # 自定义的 可以不定义
# # print('子进程:%d' % os.getpid())
# #
# # if __name__ == '__main__':
# # p = MyProcess(1,2)
# # p.start() # ---> run方法
# # # p.walk() # ---> 在主进程中调用
# # print('主进程 :',os.getpid())
#
# # 数据隔离
# # 进程与进程之间的数据是共享的
# from multiprocessing import Process
# n = 100
# def func():
# global n
# n = n - 1
# print(n)
# if __name__ == '__main__':
# for i in range(10):
# p = Process(target=func)
# p.start()
# p.join()
# print('主进程 :',n)
import os
from multiprocessing import Process
class MyProcess(Process):
def __init__(self,arg1,arg2,arg3):
super().__init__()
self.arg1 = arg1
self.arg2 = arg2
self.arg3 = arg3
def run(self):
print('子进程 : ',os.getpid(),self.arg1,self.arg2,self.arg3)
self.walk() # walk方法会在子进程中执行
def walk(self):
print('子进程 : ',os.getpid())
if __name__ == '__main__':
p = MyProcess(1,2,3)
p.start() # 会默认调用run方法
p.walk() # walk方法直接在主进程中调用 并没有在子进程中执行
print('主进程 :',os.getpid())
# 必须创建一个类 必须继承Process类
# 必须实现一个run方法
# 实例化MyProcess得到一个对象
# 使用对象调用start方法
#
进程操作实例和其它进程的方法
#server.python
import socket;
from multiprocessing import Process;
def talk(conn):
conn.send(b'connected')
ret = conn.recv(1024)
print(ret)
if __name__ == "__main__":
sk = socket.socket();
sk.bind(("127.0.0.1", 8081));
sk.listen();
while True:
conn, addr = sk.accept();
p = Process(target=talk, args=(conn,));
p.start();
conn.close();
sk.close();
#client.python
import socket;
sk = socket.socket();
sk.connect(('127.0.0.1', 8081));
ret = sk.recv(1024);
print(ret);
inp = input(">>>");
sk.send(inp.encode('utf-8'));
sk.close();
# start 开启一个进程
# join 让主进程等待子进程结束
#
# 守护进程
# 守护进程会随着主进程的结束而结束
# 如果子进程没有执行完,主进程要一直等着
# 守护进程中不能再开启子进程
import time;
from multiprocessing import Process;
def func():
print("-"*10);
def cal_time():
# p = Process(target=func);
# p.start();
while True:
time.sleep(1);
print('过去了1秒');
if __name__ == "__main__":
p = Process(target=cal_time);
p.daemon = True #一定要在开启之前设置
p.start();
for i in range(100):
time.sleep(0.1)
print("*"*i);
import time;
from multiprocessing import Process;
def func():
print("wahaha");
time.sleep(5);
print('qqxing');
if __name__ == "__main__":
p = Process(target=func);
p.start();
print(p.is_alive());#进程是否存在
time.sleep(0.1);
p.terminate();#结束一个进程
print(p.is_alive());
time.sleep(2);
print(p.is_alive());
import time;
from multiprocessing import Process;
def func():
print("wahaha");
time.sleep(5);
print('qqxing');
if __name__ == "__main__":
p = Process(target=func);
p.start();
print(p.is_alive());#进程是否存在
time.sleep(0.1);
print(p.name, p.pid);#查看进程名字和id
p.name = "zhongzheng";
print(p.name)
p.terminate();#结束一个进程
print(p.is_alive());
time.sleep(2);
print(p.is_alive());
import time;
from multiprocessing import Process;
class MyProcess(Process):
def run(self):
print('wahaha', self.name, self.pid);
time.sleep(5);
print('qqxing', self.name, self.pid);
if __name__ == "__main__":
p = MyProcess();
p.start();
print("pid:", p.pid);
# from multiprocessing import Lock;
# lock = Lock()
#
# lock.acquire(); #需要锁,拿钥匙
# # lock.acquire(); #需要锁,阻塞
# lock.release(); #释放锁,还钥匙
# 锁就是在并发编程中 保证数据安全
from multiprocessing import Lock;
from multiprocessing import Process;
import time;
import json;
import random;
def search():
with open('ticket') as f:
print(json.load(f)['count']);
def get(i):
with open('ticket') as f:
ticket_num = json.load(f)['count'];
time.sleep(random.random());
if ticket_num > 0:
with open('ticket', 'w') as f:
json.dump({'count': ticket_num-1}, f);
print("%s买到票了"%i);
else:
print("%s没票了"%i);
def task(i, lock):
search();
lock.acquire();
get(i);
lock.release();
if __name__ == "__main__":
lock = Lock();
for i in range(20):
p = Process(target=task, args=(i, lock));
p.start();
from multiprocessing import Process;
from multiprocessing import Semaphore;
import random;
import time;
def sing(i, sem):
sem.acquire();
print("%s: 进入 ktv"%i);
time.sleep(random.randint(0, 10));
print("%s: 出 ktv"%i);
sem.release();
if __name__ == '__main__':
sem = Semaphore(4);
for i in range(20):
Process(target=sing, args=(i, sem)).start();
#生产者消费者模型.py
import time;
import random;
from multiprocessing import Queue;
from multiprocessing import Process;
def producer(q, food):
for i in range(5):
q.put('%s-%s'%(food,i))
print("生产了%s"%food);
time.sleep(random.random());
q.put(None)
q.put(None)
q.put(None)
def consumer(q, name):
while True:
food = q.get();
if food == None:break;
print("%s吃了%s"%(name, food));
if __name__ == "__main__":
q = Queue();
p1 = Process(target=producer, args=(q, "泔水"));
p1.start();
p2 = Process(target=producer, args=(q, "甜水"));
p2.start();
c1 = Process(target=consumer, args=(q, "alex"));
c1.start();
c2 = Process(target=consumer, args=(q, "老三"));
c2.start();
c3 = Process(target=consumer, args=(q, "老二"));
c3.start();
# 队列安全
# 生产者消费者模型
# 1.消费者要处理多少数据是不确定的
# 2.所能只能用while循环来处理数据,while循环无法结束,
# 3.需要生产者发送信号
# 4.有多少个消费者,就需要发送多少个信号
# 5.但是发送的信号数量需要根据生产者和消费者的数量进行计算,所以非常不便
# put q.join
# get 处理数据 task_done消费完了
import time;
import random;
from multiprocessing import JoinableQueue;
from multiprocessing import Process;
def producer(q, food):
for i in range(5):
q.put('%s-%s'%(food,i))
print("生产了%s"%food);
time.sleep(random.random());
q.join();
def consumer(q, name):
while True:
food = q.get();
if food == None:break;
print("%s吃了%s"%(name, food));
q.task_done();
if __name__ == "__main__":
q = JoinableQueue();
p1 = Process(target=producer, args=(q, "泔水"));
p1.start();
p2 = Process(target=producer, args=(q, "甜水"));
p2.start();
c1 = Process(target=consumer, args=(q, "alex"));
c1.daemon = True;
c1.start();
c2 = Process(target=consumer, args=(q, "老三"));
c2.daemon = True;
c2.start();
c3 = Process(target=consumer, args=(q, "老二"));
c3.daemon = True;
c3.start();
p1.join() #等待p1执行完毕
p2.join() #等待p2执行完毕
#生产者生产的数据全部被消费 ————生产者进程结束————主进程代码执行结束——消费者守护进程
# ipc机制——队列
# ipc机制——管道
from multiprocessing import Pipe;
p1, p2 = Pipe();#支持双向通信管道
p1.send('hello');
print(p2.recv());
p2.send('hi');
p2.close()
print(p1.recv());
print(p1.recv());
#关于管道: 双方通信
# ipc机制——队列
# ipc机制——管道
# from multiprocessing import Pipe;
# p1, p2 = Pipe();#支持双向通信管道
#
# p1.send('hello');
# print(p2.recv());
#
# p2.send('hi');
# p2.close()
# print(p1.recv());
# print(p1.recv());
#关于管道: 双方通信
from multiprocessing import Process;
from multiprocessing import Pipe
def func(p):
foo, son = p;
foo.close();
print(son.recv());
if __name__ == '__main__':
foo, son = Pipe();
p = Process(target=func, args=((foo, son),));
p.start();
son.close();
foo.send('hello');
foo.close();
# ipc机制——队列
# ipc机制——管道
# from multiprocessing import Pipe;
# p1, p2 = Pipe();#支持双向通信管道
#
# p1.send('hello');
# print(p2.recv());
#
# p2.send('hi');
# p2.close()
# print(p1.recv());
# print(p1.recv());
#关于管道: 双方通信
from multiprocessing import Process;
from multiprocessing import Pipe
from multiprocessing import Lock;
def func2(p):
foo, son = p;
son.close();
for i in range(10):
foo.send(i);
foo.close();
def func(p, lock):
foo, son = p;
foo.close();
while True:
try:
lock.acquire();
print(son.recv());
lock.release();
except EOFError:
lock.release();
son.close();
break;
if __name__ == '__main__':
lock = Lock();
foo, son = Pipe();
p1 = Process(target=func, args=((foo, son), lock));
p1.start();
p2 = Process(target=func, args=((foo, son), lock));
p2.start();
p3 = Process(target=func2, args=((foo, son), ));
p3.start();
p4 = Process(target=func2, args=((foo, son), ));
p4.start();
son.close();
foo.close();
#队列 = 管道+锁 安全
#进程之间数据不安全,没有锁的机制
# Manager是一个类,提供了可以进行数据共享的一个机制,提供了很多数据类型 dict list
from multiprocessing import Manager;
if __name__ == '__main__':
m = Manager();
d = m.dict();
print(d);
d['count'] = 0;
print(d);
#同步
from multiprocessing import Manager,Process;
def work(d):
print(d);
d['count'] -= 1;
if __name__ == '__main__':
m = Manager();
dic = m.dict({'count':100});
for i in range(100):
p = Process(target=work, args=(dic,));
p.start();
p.join(); #等待子进程结束
#异步
from multiprocessing import Manager
from multiprocessing import Process, Lock;
def func(d, lock):
# print(d)
lock.acquire();
d["count"]-=1
lock.release();
if __name__=="__main__":
lock = Lock();
m=Manager()
d=m.dict({"count":10})
l=[] # 存放开启的进程
for i in range(10):
p=Process(target=func,args=(d, lock))
p.start()
# p.join() # 判断该子进程是否结束,结束了才会继续开下一个进程(所以这样就会变成同步的)
l.append(p) # 把开启的进程放在列表中
[p.join() for p in l] # 把刚才开的10个进程放在列表,该语句执行代表开的10个进程全部结束
print(d)
# Manager dict list pipe 并不提供数据安全支持
进程池
# 进程能无限开吗
# cpu 16核处理16个任务
# 160个进程/16 10*0.01
# 不能无限开
# 开启一个进程的时候
# 要给进程分配资源,分配内存
#值 数据结构 字典
#100个任务
#4核 --开4个进程 完成100个任务叫——进程池
#第五个任务进来, 占用进程,执行任务
#进程池
# 造一个池子,放4个进程用来完成工作
#发任务
#循环使用池子中的进程来完成任务
from multiprocessing import Pool;
import os;
import time;
import random;
def fun(i):
print(i, os.getpid());
time.sleep(random.randint(1, 3));
# print(os.cpu_count());
if __name__ == "__main__":
p = Pool(5);
p.map(fun, range(20));
p.close();#不允许再向进程池中添加任务
print('--->')
进程池与开多个进程执行时间 对比
#进程为什么出现:开过多的进程
#作用:1.开启过多进程浪费时间;2.操作系统调用太多的进程也会影响效率
from multiprocessing import Pool, Process;
import time;
def fun(i):
i += 1;
# print(os.cpu_count());
if __name__ == "__main__":
p = Pool(5);
start = time.time();
p.map(fun, range(20));#map(函数,可迭代)
p.close();#不允许再向进程池中添加任务
p.join();
print(time.time() - start);
#创建多个进程
start = time.time();
l = [];
for i in range(100):
p = Process(target=fun, args=(i,));
p.start();
l.append(p);
[i.join() for i in l]
print(time.time() - start);
效果如下:
from multiprocessing import Pool;
import time;
def func(i):
time.sleep(1);
i += 1;
# print(i);
return i+1;
if __name__ == "__main__":
p = Pool(5);
rel_l = [];
for i in range(20):
# p.apply(func, args=(i, ))#apply是同步提交任务的机制
ret = p.apply_async(func, args=(i,))#apply_async是异步提交任务的机制
rel_l.append(ret);
# print(ret.get()); #阻塞:等待着任务结果
p.close();#必须有 close必须在join()之前,不允许再添加新的任务了
p.join();#必须有 等待子进程结束再往下执行
[print(i.get()) for i in rel_l]
事件
# from multiprocessing import Event;
# e = Event();#实例化一个事件 标志/交通信号灯/默认是红灯
# e.set(); #将标志变成非阻塞/交通灯变绿
# e.wait(); #刚实例化出来的一个事件对象,默认的信号是阻塞信号/默认是红灯
# #执行到wait,要先看灯,绿灯行红灯停,如果在停的过程中灯绿了,就变成非阻塞了
#
# e.clear() #将标志又变成阻塞/交通灯变红
#
# e.is_set() #看这个事件是否阻塞,True就是绿灯,False是红灯
import time;
import random;
from multiprocessing import Event, Process;
def traffic_light(e):
while True:
if e.is_set():
time.sleep(3);
print('红灯亮');
e.clear();
else:
time.sleep(3);
print("绿灯亮");
e.set();#红灯变绿灯
def car(i, e):
e.wait();
print("%s车通过"%i);
if __name__ == "__main__":
e = Event();
p = Process(target=traffic_light, args=(e,));
p.start();
for i in range(100):
if i%6 == 0:
time.sleep(random.randint(1, 3));
car_pro = Process(target=car, args=(i, e))
car_pro.start();
队列
# from multiprocessing import Queue;
# q = Queue();
# q.put(1);
# q.put(2);
# q.put(3);
#
# print(q.get());
# print(q.get());
# print(q.get());
# print(q.get());#如果队列里已经没有值了,就会阻塞等待一个有值
# 进程之间通信可以使用Queue模块
#队列创建有两种方式,一种不传参数,队列没有长度限制;传参数,创建一个最大长度限制
#提供两个重要方法:put get
#qsize
from multiprocessing import Queue;
from multiprocessing import Process;
def q_put(q):
q.put("hello");
def q_get(q):
print(q.get());
if __name__ == "__main__":
q = Queue();
p = Process(target=q_put, args=(q,));
p.start();
p1 = Process(target=q_get, args=(q,));
p1.start();
#通过队列实现了主进程与子进程的通信,子进程与子进程之间的通信
#生产者消费者模型
#我要生产一个数据然后给一个函数,让这个函数依赖这个数据进行运算,拿到结果 ——同步过程
from multiprocessing import Queue;
from multiprocessing import Process;
import time;
def producer(q):#生产者
for i in range(100):
q.put("包子%s"%i);
def consumer(q):#消费者
for i in range(100):
time.sleep(1);
print(q.get());
if __name__ == "__main__":
q = Queue(10);#托盘
p = Process(target=producer, args=(q,));
p.start();
c = Process(target=consumer, args=(q,));
c.start();
c2 = Process(target=consumer, args=(q,));
c2.start();
#对于内存空间来说,每次只有很少的数据会在内存中
#对于生产与消费之间的不平衡来说
# 增加消费者或生产者来调节效率
import requests;
ret = requests.get("http://www.baidu.com")
print(ret);
print(ret.text);#整个网页的源代码
print(ret.status_code);#状态码
# 进程之间的通信 IPC
# 队列 生产者消费者模型 *****
# joinablequeue 队列可以感知到数据的处理 taskdone q.join()
# Pipe 管道
# Manager模块里面又提供了很多数据类型来进行进程之间的数据共享,但是几乎数据都不安全
# def func(dic,lock):
# lock.acquire()
# dic['count'] += 1
# lock.release()
# print(dic) #
#
# m = Manager()
# dic = m.dict()
# dic['count'] = 0
# lock = Lock()
# for i in range(100):
# p = Process(target=func,args=(dic,lock))
# p.start()
# p.join()
# 进程池
# 进程池为什么出现 :开过多的进程 1.开启进程浪费时间 2. 操作系统调度太多的进程也会影响效率
# 开进程池 : 有几个现成的进程在池子里,有任务来了,就用这个池子中的进程去处理任务,
# 任务处理完之后,再把进程放回池子里,池子中的进程就能去处理其他任务了。
# 当所有的任务都处理完了,进程池关闭,回收所有的进程
# 开的进程数 :cpu_count + 1
# import time
# from multiprocessing import Pool
# def fun(i):
# time.sleep(1)
# i+=1
# return i
#
# if __name__ == '__main__':
# p = Pool(4)
# res_l = []
# for i in range(10):
# res = p.apply_async(fun,args=(i,)) #apply 是同步调用 顺序执行代码 target
# res_l.append(res)
# p.close() # 不能再往进程池中添加新的任务
# p.join() # 阻塞等待 执行进程池中的所有任务直到执行结束
# # apply_async是一个异步调用
# # 和主进程也异步了
# [print(res.get()) for res in res_l] # 异步调用获取函数的返回值
# import time
# from multiprocessing import Pool
# def fun(i):
# time.sleep(1)
# i+=1
# return i
# if __name__ == '__main__':
# s = time.time()
# p = Pool(4)
# ret = p.map(fun,range(10)) # func(next(range(10)))
# print(ret)
# print(time.time() - s)
# apply apply_async map
# import os
# import time
# from multiprocessing import Pool
# # 参数 概念 回调函数
# def func(i): # 多进程中的io多,
# print('子进程%s:%s'%(i,os.getpid()))
# return i*'*'
#
# def call(arg): # 回调函数是在主进程中完成的,不能传参数,只能接受多进程中函数的返回值
# print('回调 :',os.getpid())
# print(arg)
#
# if __name__ == '__main__':
# print('---->',os.getpid())
# p = Pool(5)
# for i in range(10):
# p.apply_async(func,args=(i,),callback=call)
# p.close()
# p.join()
# 例子
# 请求网页
# 网络延时 IO操作
# 单进程
# 10个页面 同时访问多个 —> 多进程
# 分析页面:长短 ——>回调函数
# from urllib.request import urlopen
import requests
from multiprocessing import Pool
def get_url(url):
ret = requests.get(url)
return {'url':url,
'status_code':ret.status_code,
'content':ret.text}
def parser(dic):
print(dic['url'],dic['status_code'],len(dic['content']))
# 把分析结果写到文件里
# if __name__ == '__main__':
# url_l = [
# 'http://www.baidu.com',
# 'http://www.sogou.com',
# 'http://www.hao123.com',
# 'http://www.yangxiaoer.cc',
# 'http://www.python.org'
# ]
# p = Pool(4)
# for url in url_l:
# p.apply_async(get_url,args=(url,),callback=parser)
# p.close()
# p.join()
# pool(4)
# 如何使用进程池 —— 都可以那到返回值
# apply 同步调用 直接调用之后就获得返回值
# apply_async 异步调用
# 在完成所有进程调用之后,close表示不再接受新任务
# join 让主进程等待子进程执行结束
# 如果需要获得返回值,提交任务之后返回的对象.get()就可以获取返回值
# callback 回调函数 :主进程执行 参数是子进程执行的函数的返回值
# map(func,iterable)
Python线程
进程是资源分配最小的单位,线程是cpu调度最小的单位,每个进程中至少有一个线程。
进程和线程的关系
1.多进程开启进程的时间长,多线程开启线程的时间短
2.cpu在进程之间的切换慢,cpu在进程之间的切换快
#如果两个任务,需要共享内存,又想实现异步,使用多线程
#如果两个任务,数据需要隔离,使用多进程
多线程的好处:轻量级且同一个进程之间的多个线程资源是共享的
内存中的线程
# 进程 执行中的程序
# 线程 轻量级的进程
# 进程可以处理一个任务
# 听课 + 记笔记 + 看屏幕
# 进程 一个时间点 只能做一件事
# 三个进程 听课 记笔记 看屏幕
# 对于一个人 来说 一个人就是一个进程
# 一个人可以做的多件事情 每一件事都是一个线程
# 进程包含着线程
# GIL 全局解释器锁 Cpython解释器
# 去掉GIL 保证数据安全 细粒度的锁 效率更低
# 高计算 多进程
# 高IO 多线程 —— 爬虫 网络
# 线程 更加的轻量级
# 线程是CPU调度的最小单位
# 进程是资源分配的最小单位
# 开启线程的时空开销 都比 开启进程要小
# 且 cpu在线程之间切换 比 在进程之间切换快
# 一个程序中 可以同时有多进程和线程
# import os
# import time
# from threading import Thread
#
# def func(): # 子线程
# time.sleep(1)
# print('hello world',os.getpid())
# thread_lst = []
# for i in range(10):
# t = Thread(target=func)
# t.start()
# thread_lst.append(t)
# [t.join() for t in thread_lst]
# print(os.getpid()) # 主线程
# import os
# import time
# from threading import Thread
#
# class MyThread(Thread):
# count = 0 # 静态属性
# def __init__(self,arg1,arg2):
# super().__init__()
# self.arg1 = arg1
# self.arg2 = arg2
# def run(self):
# MyThread.count += 1
# time.sleep(1)
# print('%s,%s,%s,%s'%(self.arg1,self.arg2,self.name,os.getpid()))
#
# for i in range(10):
# t = MyThread(i,i*'*')
# t.start()
# print(t.count)
# 计算开启的线程数量
# 多个子线程 共享 这个数据
import time
import threading
def func(i):
time.sleep(0.5)
print(i,threading.currentThread().name,threading.currentThread().ident)
# ident 线程id
for i in range(10):
t = threading.Thread(target=func,args=(i,))
t.start()
# print(len(threading.enumerate())) # 返回正在运行着的线程列表
print(threading.activeCount())
# 作业
# 1.开进程池回调函数 把分析结果写进文件里
# 2.用多线程实现socket并发的server
# 仿照多进程
# 复习
# 函数 面向对象 网络编程 并发编程
#server.py
import socket;
from threading import Thread;
def func(conn):
conn.send(b'hello');
ret = conn.recv(1024);
print(ret);
conn.close();
sk = socket.socket();
sk.bind(('127.0.0.1', 8080));
sk.listen();
while True:
conn, addr = sk.accept();
Thread(target=func, args=(conn,)).start();
import socket;
sk = socket.socket();
sk.connect(('127.0.0.1', 8080));
ret = sk.recv(1024);
print(ret);
msg = input('>>>');
sk.send(msg.encode('utf-8'));
sk.close();
线程锁
import time
from threading import Thread
from threading import Lock
def func():
global n
time.sleep(2)
lock.acquire()
temp = n # 从进程中获取n
time.sleep(0.01)
n = temp-1 # 得到结果,再存储回进程
lock.release()
n = 100
lock = Lock()
t_lst = []
for i in range(100):
t = Thread(target=func)
t.start()
t_lst.append(t)
[t.join() for t in t_lst]
print(n)
# GIL 不是锁数据 而是锁线程
# 在多线程中 特殊情况 仍然要加锁 对数据
# 慢 join lock
线程信号量
# 信号量
# 事件
# 条件
# 定时器
# 队列
import time
import random
from threading import Thread
from threading import Semaphore
def func(n,sem):
sem.acquire()
print('thread -%s start'%n)
time.sleep(random.random())
print('thread -%s done' % n)
sem.release()
sem = Semaphore(5) # 一把锁有5把钥匙
for i in range(20):
Thread(target=func,args=(i,sem)).start()
# 信号量 和 线程池 有什么区别?
# 相同点 在信号量acquire之后,和线程池一样 同时在执行的只能有n个
# 不同点
# 开的线程数不一样 线程池来说 一共就只开5个线程 信号量有几个任务就开几个线程
# 对有信号量限制的程序来说 可以同时执行很多线程么?
# 实际上 信号量并不影响线程或者进程的并发,只是在加锁的阶段进行流量限制
线程事件
# Event
# flag 标志
# 刚刚创建的时候 flag = False
# wait() flag=False 阻塞
#flag = True 非阻塞
# set() False --> True
# clear() True --> False
# 连接mysql数据库
# 我连接三次数据库
# 每0.5秒连接一次
# 创建一个事件 来标志数据库的连接情况
# 如果连接成功,就显示成功
# 否则 就报错 主动抛异常TimeoutError
import time
import random
from threading import Event
from threading import Thread
def conn_mysql(): # 连接数据库
count = 1
while not e.is_set(): # 当事件的flag为False时才执行循环内的语句
if count>3:
raise TimeoutError
print('尝试连接第%s次'%count)
count += 1
e.wait(0.5) # 一直阻塞变成了只阻塞0.5
print('连接成功') # 收到check_conn函数内的set指令,让flag变为True跳出while循环,执行本句代码
def check_conn():
'''
检测数据库服务器的连接是否正常
'''
time.sleep(random.randint(1,2)) # 模拟连接检测的时间
e.set() # 告诉事件的标志数据库可以连接
e = Event()
check = Thread(target=check_conn)
check.start()
conn = Thread(target=conn_mysql)
conn.start()
线程队列
import queue
# q = queue.Queue() # 队列 线程安全的
# q.get()
# q.put()
# q.qsize()
# lfq = queue.LifoQueue() # 后进先出 :栈
# lfq.put(1)
# lfq.put(2)
# lfq.put(3)
# lfq.put(4)
# print(lfq.get())
# print(lfq.get())
# print(lfq.get())
# print(lfq.get())
# []
import queue
pq = queue.PriorityQueue() # 值越小越优先,值相同就asc码小的先出
pq.put((1,'z'))
pq.put((1,'b'))
pq.put((15,'c'))
pq.put((2,'d'))
#
print(pq.get())
print(pq.get())
# 线程版本的生产者消费者模型 多线程+Queue —— 作业
import time
import random
from concurrent import futures
def funcname(n):
print(n)
time.sleep(random.randint(1,3))
return n*'*'
def call(args):
print(args.result())
thread_pool = futures.ThreadPoolExecutor(5)
# thread_pool.map(funcname,range(10)) # map,天生异步,接收可迭代对象的数据,不支持返回值
# f_lst = []
# for i in range(10):
# f = thread_pool.submit(funcname,i) # submit 合并了创建线程对象和start的功能
# f_lst.append(f)
# thread_pool.shutdown() # close() join()
# for f in f_lst: # 一定是按照顺序出结果
# print(f.result()) #f.result()阻塞 等f执行完得到结果
# 回调函数 add_done_callback(回调函数的名字)
thread_pool.submit(funcname,1).add_done_callback(call)
# 统一了入口和方法 简化了操作 降低了学习的时间成本
# 作业一 —— 线程版本的生产者消费者模型 多线程+Queue
# 作业二 —— 爬取网页 线程池实现
# 4核
# 进程4-5个+线程 20个线程 = 100
# 线程池 和 进程池
# 是用来做池操作的最近新的模块
# 开启线程需要成本 成本比开启进程要低
# 高IO的情况下 开多线程
# 所以我们也不能开启任意多个线程
# 开启线程池
# futures.ThreadPoolExecutor # 线程池
# futures.ProcessPoolExecutor # 进程池
# 进程池 cpu个数 + 1
# 线程池 默认 :cpu个数 * 5 4核*5 20个线程