任务:![](https://img-blog.csdnimg.cn/8160f6149b3f45b7963659a385fe938f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6ZOB6ZSk5biu5biu5Li7,size_20,color_FFFFFF,t_70,g_se,x_16)
作业:
import threading#导入threading库
import time#导入time库
class Get_time(object):#创建类Get_time 用于获取当前时间
def __init__(self,each_time_time):#设置__init__ 要一个变量each_time_time来获取每次打印的间隔
self.each_time_time=each_time_time
def print_time(self):#设置打印函数的方法 每秒循环输出当前的年月日时分秒
while True:
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))
time.sleep(self.each_time_time)
class Get_name(object):#创建类Get_name 用于获取姓名
def __init__(self,name,number,each_name_time):#设置__init__ 要3个变量name,number,each_name_time 分别要 打印的名字 打印的次数 打印的间隔
self.name=name
self.number=number
self.each_name_time=each_name_time
def print_name(self):#设置打印函数的方法 实现张三的姓名每2秒打印输出4次结束
for i in range(self.number):
print(self.name)
time.sleep(self.each_name_time)
class Do_it(Get_name,Get_time):#创建类Get_name 用于实现多线程 并完善两个类
def __init__(self,each_time_time,name,number,each_name_time):#设置__init__ 要4个变量each_time_time来获取每次打印时间的间隔 name,number,each_name_time 分别要 打印的名字 打印的次数 打印的间隔
Get_time.__init__(self,each_time_time)#再次加入父类Get_time
Get_name.__init__(self,name,number,each_name_time)#再次加入父类Get_name
def go_threading(self):#设置两个线程 同时运行时间和姓名的打印
threading1=threading.Thread(target=self.print_time)#线程1来打印时间
threading2=threading.Thread(target=self.print_name)#线程1来打印姓名
threading1.start()#线程1开始
threading2.start()#线程2开始
c1=Do_it(each_time_time=1,name="张三",number=4,each_name_time=2)#实例化一个类 为c1 每秒循环输出当前的年月日时分秒 实现张三的姓名每2秒打印输出4次结束
c1.go_threading()#运行c1中的go_threading方法 也就是线程的建立和开始
笔记:
优缺点分析:
多进程Process(multiprocess)
- 优点:可以利用多核CPU并行运算
- 缺点:占用资源最多、可启动数目比线程少
- 适合于:CPU密集型计算
多线程 Thread(Threading)
- 优点:相比进程,更轻量级,占用资源少
- 缺点:
- 相比进程:多线程只能并发执行、不能利用多CPU(GIL)
- 相比协程:启动的数目有限制,占用内存资源,有线程切换开销
- 适合于:IO密集型计算、同时运行的任务数目要求不多
多协程 Coroutine(asyncio)
- 优点:内存开销最小、启动协程数量多
- 缺点:支持的库有限制(aiohttp vs requests)、代码实现复杂
- 使用于:IO密集型计算、需要超多任务运行。但有现成库支持的场景。
threading
多线程
1.简单介绍怎么创建多线程
1.准备一个函数
def my_func(a,b):
do_craw(a,b)#意思就是对a和b进行编辑#craw喂
2.创建一个线程
import threading
thread=threading.Thread(target=my_fanc,args=(a,b))
3.启动线程
thread.start()
4.等待结束
thread.join()
.lock 用于解决线程安全问题
用法1:
import threading
lock = threading.lock()
lock.acquire()
try:
#do something
except:
lock.release()
用法2:
import threading
lock=threading.lock()
with lock:
#do something
例:
func.py
import threading
import time
lock = threading.Lock()
class Account:
def __init__(self,balance):
self.balance=balance
def draw(account,amount):
with lock:
if account.balance>=amount:
time.sleep(0.1)
print(threading.current_thread().name,'取钱成功')
account.balance=account.balance-amount
print(threading.current_thread().name,'余额:',account.balance)
else:
print(threading.current_thread().name,'余额不足')
main.py
import func
import threading
if __name__=='__main__':
account=func.Account(1000)
thread1=threading.Thread(name='thread1',target=func.draw,args=(account,800))
thread2=threading.Thread(name='thread2', target=func.draw, args=(account,800))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
线程池
1线程池原理:
新建线程系统需要分配资源,终止线程系统需要回收资源,如果可以重用线程,则可以减去新建/终止的开销
线程池好处:
- 1) 提升性能:因为减去了大量新建、终止线程的开销,重用了线程资源;
- 2) 适用场合:适合处理突发性大量请求或需要大量线程完成任务、但实际任务处理时间短
- 3) 防御功能:能有效避免系统因为创建线程过多,导致系统负荷过大变慢等问题。
- 4) 代码优势:使用线程池的语法比自己新建线程执行线程更加简洁
2ThreadPoorExecutor的使用方法
#Executor 执行人
from concurrent.futures import ThreadPoolExecutor
with ThreadPoorExecutor() as poor:
results=pool.map(func_name,urls)
for result in results:
print(result)
from concurrent.future import ThreadPoolExecutor , as_completed
pool = ThreadPoolExecutor()
futures=[poor.submit(craw,url) for url in urls]
for future in futures:
print(future.result())
for future in as_completed(futures):
print(future.result())