Python的threading
模块松散地基于Java的threading
模块。但现在线程没有优先级,没有线程组,不能被销毁、停止、暂停、开始和打断。 Java Thread
类的静态方法,被移植成了模块方法。
main thread
: 运行python程序的线程
daemon thread
守护线程,如果守护线程之外的线程都结束了。守护线程也会结束,并强行终止整个程序。不要在守护进程中进行资源相关操作。会导致资源不能正确的释放。在非守护进程中使用Event
。
Thread 类
(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
group: 为以后的ThreadGroup类预留
target: 被执行的对象,由run()方法执行
args: target对象使用的参数
daemon: 是否为守护进程
start()
每个thread 对象都只能被调用1次start()
run()
如果创建Thread的子类,重写该方法。负责执行target参数传来的可执行对象。
join()
阻塞线程直到结束。
GIL
在CPython
中,由于GIL的存在,Python
每次只能执行一个线程。如果要充分利用多核机器的计算资源需要使用multiprocessing
或者是concurrent.futures.ProcessPollExecutor
。 但,但如果你想要很多I/O相关的并发操作,threding仍然是一个很好的选择 。?因为系统自动实现了线程的上下文切换。
from threading import Thread
import requests
url = 'http://www.baidu.com'
urls = [url]*20
threads = []
for url in urls:
t = Thread(target=requests.get, args=(url, ))
t.start()
threads.append(t)
for t in threads:
t.join()
锁(Lock)对象
原始锁(primitive lock
),当它锁住的时候,它是一种不属于任何一个线程的同步原语(synchronization primitive
)。 在Python
中,他是目前可用的最底层的同步原语,由_thread
模块提供。
一个原始锁有两个状态:locked
和unlocked
。锁创建时,处于unlocked
状态。 锁由两个基本方法:acquire()
和release()
。
当处于unlocked
状态时,acquire(()
方法可以将状态变为locked
,并立即返回。当处于locked
状态时,acquire()
会阻塞直至另一个线程调用了release()
使改锁解锁,然后acquire()
将锁上锁,并返回。
release()
方法只能在锁locked
时别调用,并释放锁。否则会抛出RuntimeError
错误。
如果有多个 acquire()
在等待解锁,则不确定哪一个哪一个会被触发。
class threading.Lock
如果一个线程acquire
了一个锁,那么后续获取它的线程都会被阻塞,直至锁被释放。任何线程都可以释放锁。
Lock
是一个工厂函数,返回当前平台下最高效的concrete Lock
类的实例。
Lock
支持上下文管理方法(context management protocol
),也就是with
语句。在存在竞态条件(race condition
)的时候,要使用锁。比如多线程共同操作某个数据。
# 摘自python Cookbook
import threading
class SharedCounter:
def __init__(self, init_value=0):
self._value = init_value
self._value_lock = threading.Lock()
def incr(self, delta=1):
# 在这里使用了with 语句,创建一个锁,增加值,释放锁。
with self._value_lock:
self._value += 1
RLock对象
可重入锁(reentrant lock
)。感觉是一个锁中锁,就是可以递归的锁。等见到具体的应用例子再写。
Condition对象
condition
变量总是与某种锁相关,锁可以是传过来的,也可以通过默认设置创建。如果有多个 condition
对象需要共享一个锁时,传递一个锁是非常有用的。锁是condition
对象的一部分,你不用刻意的跟踪它。
Timer对象
Timer
是Thread
的子类,所以也要接受function
参数,也可以被start()
。 它的run()
函数被重写为先event.wait(interval)
,再启动function
。
Barrier对象
实现某些服务的共进退。
threading.Barrier(parties, action=None, timeout=None)
设置n=parties
个线程,当n
个barrier.wait()
被调用后,所有这些调用的阻塞被同时解除,执行action
感觉Barrier
可以实现很多复杂的功能。