多线程使用
发布日期:2022-04-11 08:52:51 浏览次数:7 分类:技术文章

本文共 4067 字,大约阅读时间需要 13 分钟。

多线程

# 1. 导入模块import threading# 创建线程(让每一个线程去执行这个函数(有参数就给参数))t = threading.Thread(target=函数名,args=())# 线程开始工作t.start()

多进程

# 导包import multiprocessing# 创建进程(进程创建之后,在进程中还会创建一个线程)t = multiprocessing.Process(target=函数名,args=())#启动线程t.start()代码要放在  中if __name__ == '__main__':在linux系统中没有这句不会报错# 因为linux系统 支持模式fork;  win :spawn; mac支持:fork和spawn(但是在python3.8以后默认设置为spawn)python机制导致的问题# 在最开头加一句  更改设置multiprocessing.set_start_method('fork')

多进程开销比多线程大

GIL锁

CPython解释器中的一个全局解释器锁# 让一个进程同一时刻只能由一个线程可以被cpu调用# 想要利用计算机多核优势,让cpu同时处理一些任务,适合用多进程开发(资源开发大)# 不需要利用多核优势,可以用多线程计算密集型: 多进程  大量数据计算io秘密集型:多线程  文件读写,网络数据传输(下载视频)

多线程开发

程序最开始运行的时候,它内部会先创建一个线程,而一个进程里面模式是有一个主线程

主线程会执行完所有代码,不结束(等待子线程)

常用方法

t.start()

# 当前线程准备就绪(等待CPU调度,具体时间由cpu决定)

t.join()

# 等待当前线程的任务执行完毕后,向下继续执行就是主线程遇到t.join()# 主线程等待,直到子线程结束,再向下执行如果有多个子线程t1.start() 			# t1开始执行t1.join()			# t1运行完毕,再往下运行t2.start()			#  t2开始执行t2.join()			# t2运行完毕,再往下运行# 案例	两个线程同步做。cpu在执行任务时,分片机制,cpu会分片的执行,t1执行	几个步骤,t2执行几个步骤,cpu在两个线程中来回切。t1.start()t2.start()t1.join()t2.join()

t.setDaemon(布尔值)

# 守护线程(必须放在start之前)t.setDaemon(True)	设置守护线程。主线程完毕后,子线程也会自动关闭。t.setDaemon(False)	设置非守护线程。主线程等待子线程,子线程执行完毕后,主线程才关闭(默认)。

t.setName() getName()

t.setName()  # 案例t = threading.Thread(target=XXX,args=())t.setName('线程1')t.start()	setName要放在start之前。不然设置不上getName()name = threading.current_thread().getName()

自定义线程类

import threadingclass MyThread(threading.Thread):    def run(self):     	print('执行此此线程',self._args)   t = MyThread(args=(100,))t.start()

线程安全

创建锁

lock_object = threading.RLock()

加锁:

lock_object.acquire()

释放锁

lock_object.release()

# 他们必须用同一把锁谁是第一个到的,谁就把锁申请到了,然后加锁,继续往下执行。而没有申请到这把锁的就要等待。等待加锁的那个释放了。
# 可以基于上下文管理,内部自动执行# acquire 和release# 就和文件操作类似with lock_object:    global num    for i in range(100):        num+=1print(num)

线程锁

一次锁一次解。lock效率高

Lock 同步锁

lock 不支持锁的嵌套# 锁了一次解开,然后再锁lock_object.acquire()...lock_object.release()lock_object.acquire()...lock_object.release()# 死锁(锁一次没解锁又锁)lock_object.acquire()...lock_object.acquire()

RLock 递归锁

# 开发中rlock用的还是比较多import threadinglock = threading.RLock()# A开发了一个函数,可以被其他人调用(有锁)def func():    with lock:        pass# B开发函数需要加锁,还要调用func()def process()	with lock:        print('...')        func()		# ........此时就会出现多次锁,只有rlock支持        print('...')

死锁

由于竞争资源或者由于彼此通信而造成的一种阻塞现象

lock_object.acquire()lock_object.acquire()...lock_object.release()lock_object.release()
import threading import timelock1 = threading.Lock()lock2 = threading.Lock()def task1():    lock1.acquire()		# 获取第一把锁    time.sleep(1)    lock2.acquire()		    print(11)    lock2.release()    print(111)    lock1.release()    print(1111)def task2():    lock2.acquire()		#获取第二把锁    time.sleep(1)    lock1.acquire()    print(22)    lock1.release()    print(222)    lock2.release()    print(2222)# 如果两个人都不释放锁,就会死锁

线程池

线程不是开的越多越好。开得多可能会导致系统的性能更低了

# 使用线程池  导包from concurrent.futures import ThreadPoolExecutor# 创建了一个线程池,最多维护100个线程pool = ThreadPoolExecutor(100)# 把一个任务交给线程池,让他安排线程帮助取执行# 线程池中如果有空闲线程,则分配一个线程去执行,执行完毕后再将线程交给线程池# 如果没有空闲线程,就等待pool.submit(函数名,参数1,...)

等待线程池的任务执行完毕

pool.shutdown(True)# 等待线程池内的任务执行完毕,再继续执行# 类似于join

add_done_callback(done)

可以做分工,task专门下载,done专门将下载的东西写入本地

future = pool.submit(task,url)future.add_done_callback(done)# 当线程执行完毕,再执行一下done函数# 线程池先去安排一个线程去执行这个任务(task),任务执行完,再执行一下done

练习题

 

单例模式

面向对象+多线程相关的面试题

class Singleton:    instance = None    lock = threading.RLock()        def __init__(self,name):        self.name = name    def __new__(cls,*args,**kwargs):        # 返回空对象        if cls.instance:            return cls.instance                with cls.lock:            if cls.instance:                return cls.instance            cls.instance = object.__new__(cls)            return cls.instance

总结

1. 简述进程线程的区别以及应用场景

1. 线程是计算机中可以被cpu调度的最小单元(真正在工作)2. 进程是计算机资源分配的最小单元2. (进程为线程提供资源)3. 一个进程可以有多个线程,同一个进程中的线程可以共享此进程中的3. 资源# 由于GIL锁的存在,控制一个进程中同一时刻只有一个线程可以被CPU调度		4. 计算密集型:适合多进程		5. IO密集型:适合多线程

2.GIL锁

GIL锁是cPython解释器特有的一个全局解释器锁。控制一个进程中同一时刻只有一个线程可以被CPU调度同时像列表。字典等常见对象的线程数据安全,也得益于GIL

3.手写单例模式

 

4. 判断

t = threading.Thread(target = wait)# 默认值。主线程不会终止,等待子线程t.setDaemon(False)# 主线程结束,子线程就结束,不会等待t.setDaemon(True)# 等子线程完了,主线程才能继续t.join()

转载地址:https://blog.csdn.net/qq_43635902/article/details/123352390 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:多线程使用~会多少?
下一篇:多线程传数据例子

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年04月10日 16时23分47秒