threading线程
在同一个进程中需要同时执行多个 “子任务” ,将这些 “子任务” 称之为线程
同一个进程中的线程共享该进程的资源
通过 threading 模块中的 Thread 类可以创建线程对象
在创建进程的时候,系统会自动创建一个主线程,每个线程都有属于自己的名称,当需要查看线程的名称的时候,可以 使用
threading.current_thread().name —> 获取当前正在执行的线程的名称
thread.current_thread() 方法可以返回线程本身
创建线程的时候可以不指定线程的名称,系统会自动默认创建,主线程的名称默认为 “MainThread” , 子线程的名称默认为 “Threaed-1、 Thread-2 …”
-
线程的创建(即创建Thread类对象)
threading.Thread(group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None) - group ---> 未来扩充线程分组时使用 - target ---> 被run() 方法调用的方法,默认None,无可执行的函数 - name ---> 线程名称, 默认为Thread-N - args ---> tuple 类型的参数 - kwargs ---> dict 类型的参数 - daemon ---> 线程是否守护进程的标志位
在线程的创建中最重要的参数是 target , target 参数接收的 “线程任务”,只有当需要通过线程执行的任务传给 target ,该线程才能正常运行
args 和 kwargs 则是给 target 接收的 “线程任务” 进行传参,“线程任务” 通常为函数或者类 ,如果 任务函数 需要传递参数的话,args可以传入固定参数, kwargs传入可变参数
线程创建完成后需要调用 start() 方法 开启线程
-
线程的方法
方法 描述 start() 启动线程 run() 表示线程的方法,可以在子类中重写该 join(timeout=None) 等待线程结束 name 线程名称 daemon 布尔值,表示线程是否为后台线程,在start()前使用,默认False,当没有活动的前台进程(非后台)进程时,Python程序退出,即通过Thread对象建立的前台进程执行全部结束,程序才退出,若主程序不结束,前台进程会一直运行,需要手动结束;设置为后台进程(daemon=True)时,主程序结束后,这些后台进程会自动结束,无需手动停止. join() 方法也可以理解为 提供当前线程阻塞,等待线程结束后,在执行下一个线程,保护线程通畅有序执行,timeout 指等待时间
如果不适用等待线程结束的方法
join
时,线程的输出结果有可能会出现线程混乱,即第一个线程开启后还没有运行结束,第二个线程已经开启了,可能会出现第二个线程先输出的情况,使用 join 时,第一个线程的任务完全结束后,才会开启第二个线程,输出的结果也将是有序的无 join 方法的混乱输出结果
有 join 的有序输出
-
线程锁
在同一进程下的线程间资源是共享的,使用线程锁可以有效的保护共享资源。资源共享意味着所有线程均可以修改资源,而线程的执行是抢占式的,cpu执行任务的时候是不定规律执行的,同时会执行多个语句,多个线程在同一个进程中可以并发执行,当第一个线程读取数据时,第二个线程在修改数据,将会导致冲突。如果发生数据修改的操作,为防止数据资源冲突,可以给线程加锁,以保护资源。
线程锁原理:只有当被加锁的线程执行完毕,并释放锁,其他线程才可以对该线程所占用的资源进行操作使用
threading 模块中提供了 Lock 类, 即线程锁
线程锁的使用主要由以下三个步骤:
lock = treading.Lock() —> 创建一个锁对象
lock.acquire() —> 获取锁/持有锁
lock.release() —> 释放锁
当线程需要修改共享资源时,先让该线程 持有锁 , 这时该线程正在操作的资源别的线程将无法访问, 当该线程操作完成后, 在将锁释放,这时该资源才能被其他线程访问使用。
也可以通过上下文管理器 with lock 的方式使用线程锁,好处在于可以自动上锁和解锁,不需要手动持有锁和释放锁