python线程(python threading模块、python多线程)(守护线程与非守护线程) 多线程入门 1. 多线程概述运行多个任务可同时进行的程序的技术是多线程, 它主要借由模块达成实现, 此模块给出许多丰富的API用以创建和管理线程, 使用多线程能够提升程序的执行效率, 特别是在执行多个相互独立的任务之际, 又或者是在开展大量的I/O操作之时。2. 模块基础在中, 模块属于用于达成多线程的标准库里面的其中一个。于这个模块当中, 涵盖着多个类, 还有多个函数, 借助这些能够协助开发者去创建, 并且管理线程。类, 此为一个用以代表线程的类, 能够借由创建该类的实例去新建一个线程。Lock类, 于多线程环境里, 因为防范数据错乱的缘故, 一般而言得用锁机制, Lock类给予了基本的锁功能, 可助力同步线程。类, 这属于一种更为高级的线程同步机制, 它于某些条件状况下会阻塞线程, 直至被其他线程唤醒。3.创建线程。使线程得以创建的基本方式乃是要对类进行实例化, 此操作会接纳一个目标函数以及该函数的参数。以下呈现的是一个简易的示例:import threading def print_numbers(n): for i in range(1, n 1): print(i) # 创建线程 thread threading.Thread(targetprint_numbers, args(10,)) # 启动线程 thread.start() # 等待线程完成 thread.join()有一段代码, 其定义了一个函数, 该函数的功能是打印数字, 并且, 这段代码还在一个新的线程之中运行这个函数。4. 线程间通信用于线程间通信的方式之中包含借助全局变量、队列等得以达成, 而queue.Queue类具备线程安全特性, 极为适宜用于线程间的数据传递。import threading import queue # 创建一个队列 q queue.Queue() def producer(): for i in range(10): q.put(i) print(fProduced {i}) def consumer(): while True: item q.get() if item is None: break print(fConsumed {item}) q.task_done() # 创建生产者和消费者线程 t1 threading.Thread(targetproducer) t2 threading.Thread(targetconsumer) t1.start() t2.start() t1.join() q.put(None) # 用None来通知消费者结束 t2.join()5. 线程同步线程同步于多线程环境里, 是极为重要的, 这能够借由锁Lock予以达成, 下述示例呈现了怎样运用锁去确保多个线程能够安全地对共享数据作出修改。import threading # 共享资源 counter 0 lock threading.Lock() def update_counter(): global counter with lock: current counter current 1 counter current print(fCounter: {counter}) threads [] for i in range(10): t threading.Thread(targetupdate_counter) t.start() threads.append(t) for t in threads: t.join()留意, t.join()属于一个会阻塞调用的操作。于一个线程里调用join()方法时, 它会将调用它的线程阻碍住一般是主线程, 一直到被调用join()的线程也就是t完成执行。这表明主线程会等待t线程结束它的运行, 之后才着手去继续执行join()后续这一代码之后进行的代码。join()方法常常被运用于切实保证线程在程序再度执行以前达成其任务, 尤其是在主线程需要从别的线程里获取结果或者在继续前行之前确保所有子线程结束的情形下。这属于一种用于对不同线程之间的执行次序予以协调的同步技术。这段代码创建了10个线程, 其中每个线程都尝试去更新全局变量, 通过运用锁lock, 从而确保了每次仅有一个线程能够进行修改。的确, 先前回答里仅仅是简略地讲述了模块的某些基础运用方式。接下来会细致地介绍模块之中几个关键的类与函数, 以及它们的参数和使用方法:模块各类详解 类类是模块中用来创建和管理线程的主要类。主要参数如下针对指定线程启动时要执行的函数, args是一个元组, 它表示传递给目标函数的参数, 还有一个是字典, 它表示传递给目标函数的关键字参数, name用来为线程指定一个名称, 这在调试时很有用, 另外还有一个布尔值, 它指示线程是否是守护线程, 也就是守护线程会随着主线程的退出而退出, 这是所说的参数 , 这就是所说的函数和参数。在特定模块里, 属性用于指明线程是不是守护线程 , 此属性获取一个布尔值 , 以界定线程行为。守护线程的特性被守护的线程常常是用于在后台运行的服务或者任务, 像是日志写入、系统监控等之类的。这些任务一般都是周期性的, 并不需要与程序主逻辑同步达成结束。将线程设置成守护线程能够避免这些后台任务使得主程序的生命周期被延长。示例守护线程与非守护线程下面的代码示例, 演示了怎样去设置守护线程, 接着观察, 守护线程与非守护线程的行为差异: 。- 守护线程主程序退出守护线程将会被强制退出import threading import time def daemon_thread(): while True: time.sleep(1) print(Daemon thread is running...) # 创建守护线程 daemon threading.Thread(targetdaemon_thread) daemon.daemon True # 启动线程 daemon.start() print(Main program exits.)不是那种守护进程, 其执行情况是, 主程序退出后, 并非守护线程就没有了, 而是依旧会执行, 一直到它把自身的运行任务全部完成才停止。import threading import time def non_daemon_thread(): for i in range(5): time.sleep(1) print(Non-daemon thread is running...) # 创建非守护线程 non_daemon threading.Thread(targetnon_daemon_thread) # 启动线程 non_daemon.start() print(Main program exits.)示例import threading def worker(num): 线程执行的目标函数 print(fWorker: {num}) threads [] for i in range(5): t threading.Thread(targetworker, args(i,), namefthread-{i}) t.start() threads.append(t) for t in threads: t.join()Lock 类Lock类用于线程同步主要方法有等于真, 等于负一, 尝试去获得锁, 当参数为假的时候, 方法会马上返回一个布尔值, 用来表明是否获取到了锁, 指定等待该锁的最长时间, 释放锁, 示例:import threading lock threading.Lock() def worker(num): lock.acquire() try: print(fWorker: {num}) finally: lock.release() threads [] for i in range(5): t threading.Thread(targetworker, args(i,)) t.start() threads.append(t) for t in threads: t.join()类信号量是一种同步机制, 它更为高级。它允许多个线程同时去访问相同的资源, 不过是存在有限制的数量的。等于真, 等于负一: 和锁的状态相同。 括号为空: 解除信号量。 例如:import threading semaphore threading.Semaphore(2) def worker(num): with semaphore: print(fWorker: {num}) threads [] for i in range(5): t threading.Thread(targetworker, args(i,)) t.start() threads.append(t) for t in threads: t.join()Event 类事件是一个简单的同步机制主要用于线程间的事件通知。将事件状态通过set()设置为真, 把事件状态借由clear()设置为假, 利用wait(None)阻塞线程, 直至事件的状态变为真或者超时, 示例:import threading event threading.Event() def waiter(event, n): print(fThread {n} waiting for event) event.wait() print(fThread {n} proceeding) def setter(event): print(Setting event) event.set() t1 threading.Thread(targetwaiter, args(event, 1)) t2 threading.Thread(targetwaiter, args(event, 2)) t3 threading.Thread(targetsetter, args(event,)) t1.start() t2.start() t3.start() t1.join() t2.join() t3.join()固然, 模块除去涵盖, Lock, 以及Event类以外, 尚存在别的一些颇具价值的同步原语与工具, 能够辅助处理线程之间的协调事宜以及状态共享问题。接下来阐述几个其他常被运用的类:类类被应用于复杂的线程同步问题, 从本质上来说它属于一种围绕锁Lock的更为高级的锁, 它能够让一个线程去等待某一个条件, 并且使得其他线程发出条件已经被满足的信号。()-(): 跟Lock一样, 用以获取以及释放底层锁。-wait(None): 让调用线程等候, 直至被()或者()叫醒亦或是超时。-(n1): 唤醒一个或者多个正等候此条件的线程。n明确要唤醒的线程数量。-(): 唤醒所有等候此条件的线程。 示例:import threading condition threading.Condition() def consumer(cond): with cond: print(Consumer waiting) cond.wait() print(Consumer proceed) def producer(cond): with cond: print(Producer ready, notifying consumer) cond.notify_all() t1 threading.Thread(targetconsumer, args(condition,)) t2 threading.Thread(targetproducer, args(condition,)) t1.start() t2.start() t1.join() t2.join()类类被用来打造一个使之同步的节点, 线程得一同抵达此节点方可接着执行。这于某些并行的算法里极为有用于其中, 要求全部并行行事的任务一并抵达某个阶段出现了计算之后才能够继续向前推进。-: 这是类构造函数的关键主要参数, 它所代表的是需要前去到达屏障点的线程数目。唯有当指定数量的线程都已经调用了wait()方法, 所有这些线程才会在同一时刻被释放进而继续执行。这个数字必须在创建之际加以确定, 且在其整个生命周期之内维持不变。 - wait(): 阻拦塞住调用此方法的线程, 直等到所有线程都已经调用此方法。随后所有线程一同同时释放。 示例:import threading barrier threading.Barrier(2) def worker(barrier, num): print(fWorker {num} reaching barrier) barrier.wait() print(fWorker {num} passed barrier) t1 threading.Thread(targetworker, args(barrier, 1)) t2 threading.Thread(targetworker, args(barrier, 2)) t1.start() t2.start() t1.join() t2.join()Timer 类Timer 是 的子类用于在指定的时间后启动一个操作。定时器激活之前, 存在着延迟时间, 这里的延迟时间是以秒为单位的。定时器激活的时候, 会有一个要去执行的函数。对于传递给该函数的参数, 是以args的形式来呈现的。这就是示例所描述的情况。import threading def delayed_function(): print(Timer activated) timer threading.Timer(5.0, delayed_function) timer.start() # 5秒后打印输出多线程程序借助这些类所提供的各异同步机制, 得以更精准地把控线程间的交互与协调。设计多线程应用之际, 知悉并挑选适宜的同步机制颇为关键, 这能够助力规避诸如死锁以及竞争条件等问题。这些类, 为多线程编程提供了丰富的支持, 这些方法, 也为多线程编程提供了丰富的支持, 使得在多种场景下, 能够有效地使用线程。以上所呈现的内容, 乃是针对多线程的一种基础性说明, 其中包含了创建线程, 以及线程间通信, 还有线程同步的基本概念与方法。于实际运用当中, 依据具体的需求去挑选恰当的同步机制以及通信方式, 这无疑是极为重要的。参考文章参考文章线程创建和传参(33)