整理关于threading的知识
线程本地数据是特定线程的数据。管理线程本地数据,只需要创建一个 local (或者一个子类型)的实例并在实例中储存属性:
mydata = threading.local()
mydata.x = 1
Thread 类代表在独立控制线程运行的活动。有两种方式指定活动:传递一个可调用对象给构造函数或者在子类重载 run() 方法。其它方法不应该在子类被(除了构造函数)重载。换句话说,只能 重载这个类的 init() 和 run() 方法。
当线程对象一旦被创建,其活动必须通过调用线程的 start() 方法开始。 这会在独立的控制线程中发起调用 run() 方法。
一旦线程活动开始,该线程会被认为是 ‘存活的’ 。当它的 run() 方法终结了(不管是正常的还是抛出未被处理的异常),就不是’存活的’。 is_alive() 方法用于检查线程是否存活。
其他线程可以调用一个线程的 join() 方法。这会阻塞调用该方法的线程,直到被调用 join() 方法的线程终结。
线程有名字。名字可以传递给构造函数,也可以通过 name 属性读取或者修改。
如果 run() 方法引发了异常,则会调用 threading.excepthook() 来处理它。 在默认情况下,threading.excepthook() 会静默地忽略 SystemExit。
一个线程可以被标记成一个“守护线程”。 这个标识的意义是,当剩下的线程都是守护线程时,整个 Python 程序将会退出。 初始值继承于创建线程。 这个标识可以通过 daemon 特征属性或者 daemon 构造器参数来设置。
start()
开始线程活动。
它在一个线程里最多只能被调用一次。 它安排对象的 run() 方法在一个独立的控制线程中被调用。
如果同一个线程对象中调用这个方法的次数大于一次,会抛出 RuntimeError 。
代表线程活动的方法。
你可以在子类型里重载这个方法。 标准的 run() 方法会对作为 target 参数传递给该对象构造器的可调用对象(如果存在)发起调用,并附带从 args 和 kwargs 参数分别获取的位置和关键字参数。
等待,直到线程终结。这会阻塞调用这个方法的线程,直到被调用 join() 的线程终结 – 不管是正常终结还是抛出未处理异常 – 或者直到发生超时,超时选项是可选的。
当 timeout 参数存在而且不是 None 时,它应该是一个用于指定操作超时的以秒为单位的浮点数或者分数。因为 join() 总是返回 None ,所以你一定要在 join() 后调用 is_alive() 才能判断是否发生超时 – 如果线程仍然存活,则 join() 超时。
当 timeout 参数不存在或者是 None ,这个操作会阻塞直到线程终结。
如果尝试加入当前线程会导致死锁, join() 会引起 RuntimeError 异常。如果尝试 join() 一个尚未开始的线程,也会抛出相同的异常。
is_alive()
返回线程是否存活。
当 run() 方法刚开始直到 run() 方法刚结束,这个方法返回 True 。模块函数 enumerate() 返回包含所有存活线程的列表。
线程启动后,python解释器给thread分配的标识
# example of reporting the thread identifier
from threading import Thread
# create the thread
thread = Thread()
# report the thread identifier
print(thread.ident)
# start the thread
thread.start()
# report the thread identifier
print(thread.ident)
-----------------------------
output
None
164284
这个是底层os分配的
# example of reporting the thread identifier
from threading import Thread
# create the thread
thread = Thread()
# report the thread identifier
print(thread.ident)
print(thread.native_id)
# start the thread
thread.start()
# report the thread identifier
print(thread.ident)
print(thread.native_id)
--------------
output:
None
None
234468
234468
说明python开启的是真实的操作系统层面上的线程
# example of setting the thread name via the property
from threading import Thread
# create a thread
thread = Thread()
# set the name
thread.name = 'MyThread'
# report thread name
print(thread.name)
indicates the number threads that are “alive“
# report the number of active threads
from threading import active_count
# get the number of active threads
count = active_count()
# report the number of active threads
print(count)
# retrieve the current thread within
from threading import Thread
from threading import current_thread
# function to get the current thread
def task():
# get the current thread
thread = current_thread()
# report the name
print(thread.name)
# create a thread
thread = Thread(target=task)
print(current_thread().name)
# start the thread
thread.start()
# wait for the thread to exit
thread.join()
print(current_thread().name)
output:
MainThread
Thread-11
MainThread
##some example
可以看到处于initial态度
没用.start()之前
原始锁是一个在锁定时不属于特定线程的同步基元组件。在Python中,它是能用的最低级的同步基元组件,由 _thread 扩展模块直接实现。
原始锁处于 “锁定” 或者 “非锁定” 两种状态之一。它被创建时为非锁定状态。它有两个基本方法, acquire() 和 release() 。当状态为非锁定时, acquire() 将状态改为 锁定 并立即返回。当状态是锁定时, acquire() 将阻塞至其他线程调用 release() 将其改为非锁定状态,然后 acquire() 调用重置其为锁定状态并返回。 release() 只在锁定状态下调用; 它将状态改为非锁定并立即返回。如果尝试释放一个非锁定的锁,则会引发 RuntimeError 异常。
锁同样支持 上下文管理协议。
当多个线程在 acquire() 等待状态转变为未锁定被阻塞,然后 release() 重置状态为未锁定时,只有一个线程能继续执行;至于哪个等待线程继续执行没有定义,并且会根据实现而不同。
所有方法的执行都是原子性的。
可以阻塞或非阻塞地获得锁。
当调用时参数 blocking 设置为 True (缺省值),阻塞直到锁被释放,然后将锁锁定并返回 True 。
在参数 blocking 被设置为 False 的情况下调用,将不会发生阻塞。如果调用时 blocking 设为 True 会阻塞,并立即返回 False ;否则,将锁锁定并返回 True。
当参数 timeout 使用设置为正值的浮点数调用时,最多阻塞 timeout 指定的秒数,在此期间锁不能被获取。设置 timeout 参数为 -1 specifies an unbounded wait. It is forbidden to specify a timeout when blocking is False 。
如果成功获得锁,则返回 True,否则返回 False (例如发生 超时 的时候)。
在 3.2 版更改: 新的 timeout 形参。
在 3.2 版更改: 现在如果底层线程实现支持,则可以通过POSIX上的信号中断锁的获取。
释放一个锁。这个方法可以在任何线程中调用,不单指获得锁的线程。
当锁被锁定,将它重置为未锁定,并返回。如果其他线程正在等待这个锁解锁而被阻塞,只允许其中一个允许。
当在未锁定的锁上发起调用时,会引发 RuntimeError。
没有返回值。
当锁被获取时,返回 True。
based program language: python
thread线程
切换的形式如下
import time
import threading
def thread_1(i):
time.sleep(2)
print("Active current thread right now:", (threading.current_thread()))
print('Value by Thread 1:', i)
def thread_2(i):
time.sleep(5)
print("Active current thread right now:", (threading.current_thread()))
print('Value by Thread 2:', i)
def thread_3(i):
print("Active current thread right now:", (threading.current_thread()))
print("Value by Thread 3:", i)
# Creating sample threads
thread1 = threading.Thread(target=thread_1, args=(1,))
thread2 = threading.Thread(target=thread_2, args=(2,))
thread3 = threading.Thread(target=thread_3, args=(3,))
print("Active current thread right now:", (threading.current_thread()))
#3 Initially it is the main thread that is active
# Starting the threads
thread1.start()
thread2.start()
thread3.start()
--------------------------------------------------------------------
output:
Active current thread right now: <_MainThread(MainThread, started 140048551704320)>
Active current thread right now: <Thread(Thread-3, started 140048508823296)>
Value by Thread 3: 3
Active current thread right now: <Thread(Thread-1, started 140048525608704)>
Value by Thread 1: 1
Active current thread right now: <Thread(Thread-2, started 140048517216000)>
Value by Thread 2: 2
t = threading.Thread(target=?,name=?,args=?) -> initialize
有以下方法:
t.start()
t.run()
t.current_thread()
t.isDaemon()
t.setName(?)
t.SetDaemon(True)
t.join()
t.is_alive()
结合thread的state模型;initiailize ready running blocked terminated 理解
实际上两者不用刻意区分两者,因为两者都会暂停线程的执行。
两者的区别是:
两者的共同点是:
threading.Condition to notify a waiting thread that something has happened.
import threading
# 可传入一个互斥锁或者可重入锁
cond = threading.Condition()
# example of wait/notify with a condition
from time import sleep
from threading import Thread
from threading import Condition
# target function to prepare some work
def task(condition, work_list):
# block for a moment
sleep(1)
# add data to the work list
work_list.append(33)
# notify a waiting thread that the work is done
print('Thread sending notification...')
with condition:
condition.notify()
# create a condition
condition = Condition()
# prepare the work list
work_list = []
# wait to be notified that the data is ready
print('Main thread waiting for data...')
with condition:
# start a new thread to perform some work
worker = Thread(target=task, args=(condition, work_list))
worker.start()
# wait to be notified
condition.wait()
# we know the data is ready
print(f'Got data: {work_list}')
作用是定时器后执行
# SuperFastPython.com
# example of using a thread timer object
from time import sleep
from threading import Timer
# target task function
def task(message):
# report the custom message
print(message)
# create a thread timer object
timer = Timer(3, task, args=('Hello world',))
# start the timer object
timer.start()
# block for a moment
sleep(1)
# cancel the thread
print('Canceling the timer...')
timer.cancel()
Three common approaches include:
1.The event class will protect a boolean variable ensuring all access and change to the variable is thread safe, avoiding race conditions
# set the event true
event.set()
# ...
# set the event false
event.clear()
# example of using an event object
from time import sleep
from random import random
from threading import Thread
from threading import Event
# target task function
def task(event, number):
# wait for the event to be set
event.wait()
# begin processing
value = random()
sleep(value)
print(f'Thread {number} got {value}')
# create a shared event object
event = Event()
# create a suite of threads
for i in range(5):
thread = Thread(target=task, args=(event, i))
thread.start()
# block for a moment
print('Main thread blocking...')
sleep(2)
# start processing in all threads
event.set()
# wait for all the threads to finish...
# acquire the lock
lock.acquire()
try:
# critical section...
finally:
# always release the lock
lock.release()
...
# create a shared lock
lock = threading.Lock()
...
# acquire the lock
with lock:
# read or write the shared variable
...
The queue module provides a number of queue types, such as:
# loop forever
while True:
# get an item of data from the queue
data = queue.get()
# ...
线程可以自己__init__属性,然后读取就行。
class MyThread(threading.Thread)
def __init__(self):
# define an instance variable
self.data = 33
# define a lock to protect the instance variable
self.lock = threading.Lock()
# method on the class
def task(self):
# acquire the lock
with self.lock:
# modify the instance variable
self.data = 22
A semaphore is essentially a counter protected by a mutex lock, used to limit the number of threads that can access a resource.
# example of using a semaphore
from time import sleep
from random import random
from threading import Thread
from threading import Semaphore
# target function
def task(semaphore, number):
# attempt to acquire the semaphore
with semaphore:
# process
value = random()
sleep(value)
# report result
print(f'Thread {number} got {value}')
# create a semaphore
semaphore = Semaphore(2) #limit the number of concurrent processing threads to 2.
# create a suite of threads
for i in range(10):
worker = Thread(target=task, args=(semaphore, i))
worker.start()
# wait for all workers to complete...