一文读懂多线程
Posted python爬虫小助手
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文读懂多线程相关的知识,希望对你有一定的参考价值。
1threading简介
我们首先看看官方文档里面关于threading这个模块的介绍。
threading模块是建立在_thread模块的高级模块,同样是一个内置模块,它具有更为高级的多线程接口。
threading中的模块接口:
threading.active_count():返回当前存货的进程数量。
threading.current_thread():返回当前线程对象,对应于调用者控制的线程。
threading.get_ident():返回当前线程的标识符,是一个非零整数,线程标识符可以在线程退出时循环使用,并且创建另一个线程。
threading.enumerate():返回当前存在的所有线程对象的列表,这个列表包含了daemonic线程和由current_thread()创建的虚拟线程对象,以及主线程。
threading.main_thread():返回主线程对象。一般情况下,主线程由python解释器开启。
threading.settrace(func):为所有线程设置追踪函数,在run方法开启前,该函数将传递给sys.settrace()。
threading.TIMEOUT_MAX:阻塞函数的超时参数允许的最大值,指定大于此值的超时将引发溢出错误。
class threading.local:代表着 thread-local 数据的类。
2threading.Thread对象
Thread类表示一个在单独的控制线程中运行的活动。
通过重写这个类的__init__()和run()方法,来指明这个线程的活性。
一旦线程被创建,调用线程的start()方法后,这个线被启动,此刻这个线程是“alive”的。线程的run()方法终止时(通常是正常的终止的),或者通过抛出未处理的异常,它将停止存活。
is_alive()方法可以用来测试线程是否存在。
所有的线程都可以调用join()方法,它将持续阻塞,直到所有执行了该方法的线程执行完毕任务之后。
调用name()方法可以获得线程的name属性。
线程都可以用setDaemon()方法标记守护线程,必须在线程启动之前设置。这个标志的意义是守护线程被守护到直至整个python程序退出前。如果希望线程优雅地停止,一定不要让它成为守护线程,可以尝试用Event事件等信号机制来实现。主线程,对应于Python程序中的初始控制线程,并不是守护线程。
class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
group是未来可能补充进来的 ThreadGroup 类的扩展;
target是run方法调用的可调用对象。
name是线程名字。
args是传入target的参数。
如果子类重写该构造函数,它必须确保在执行线程之前调用基类构造函数(thread.__init__())。
在Cpython中,基于全局解释器锁(GlobalInterpreter Lock),同一时间,只能有一个线程执行python代码(某些以性能为导向的库可能会克服这种限制),如果你希望你的应用程序充分利用电脑多核资源,可以尝试使用:
多进程或者 concurrent.futures.ProcessPoolExecutor。
Lock Objects,原始锁是一种同步原语,它在锁定时不是由特定线程拥有的。一个原始锁有两种状态,锁住或者解锁状态。线程被激活后,一般处于解锁状态。这两种状态对应着两个基本函数: acquire() 和release():acquire可以改变解锁状态为阻塞状态,当线程被锁住后,等待release回调,锁被释放,重新变为解锁状态。支持上下文管理协议。
上下文管理协议,即这个模块提供的所有对象实现acquire()和release()方法,可以作为with语句实现。
with some_lock:
# do something...
完全等价于:
some_lock.acquire()
try:
# do something...
finally:
some_lock.release()
RLock Objects,可重入锁是一个同步原语,它可以被同一个线程多次获取。与lockobject类似,拥有两个基本函数方法,只是在锁住状态时可获取多重锁,在解锁状态时被释放。支持上下文管理协议。
3线程通信
Condition Objects,条件变量也遵循上下文管理协议,来管理acquire()和release()方法;其他方法,如wait()方法释放锁,然后阻塞至另一个线程通过notify()或者notify_all()方法回调唤醒,一旦被唤醒,wait方法重新获得锁并返回。注意,notify和notify_all方法并不能释放锁,这意味着线程唤醒并不会立即从wait返回,直到被notify才会真正释放锁的占有权。
例如,生产者和消费者模型:
# Consume one item
with cv:
while not an_item_is_available():
cv.wait()
get_an_available_item()
# Produce one item
with cv:
make_an_item_available()
cv.notify()
Semaphore Objects,一个信号量管理着一个内部计数器,这个计数被每被acquire()调用一次递减,又通过每个release()调用递增。如果acquire发现这个计数是0,就会阻塞,直到其他线程调用release()。支持上下文管理协议。
class threading.Semaphore(value=1)
class threading.BoundedSemaphore(value=1)
maxconnections = 5
pool_sema =BoundedSemaphore(value=maxconnections)
with pool_sema:
conn= connectdb()
try:
# ... use connection ...
finally:
conn.close()
Event Objects,这是线程之间通信最简单的交流方式之一。一个线程设置事件,其他线程等待它。事件对象管理可以用set()方法设置为true,并使用clear()方法重置为false。wait()方法阻塞直到flag为true。
is_set():当且仅当内部标志为真时返回true
set():设置internal flag为True,所有的线程等待它为真才能唤醒。
Clear():重新设置内部flag为Fasle。调用wait()的线程将阻塞直到set()被调用,以便再次将内部flag设置为True。
wait(timeout=None):阻塞直至内部flag为True。如果内部flag为True,立即返回,否则,将会阻塞至另一个线程调用set()。
Timer Objects,这个类表示经过一定时间才能运行的操作。
class threading.Timer(interval, function,args=None, kwargs=None)
def hello():
print("hello, world")
t = Timer(30.0, hello)
t.start()
# after 30 seconds, "hello, world" will be printed
4例子
关于多线程的实例,网上有很多,这里给大家安利一个我看过的一篇公众推文,作者是大牛:
好了,线程的分享就到这里了。
本文翻译至threading官方文档,点击下方“阅读原文”进行详细了解。
o长按关注o
以上是关于一文读懂多线程的主要内容,如果未能解决你的问题,请参考以下文章