python【threading】资料堆砌

threading

整理关于threading的知识

线程本地数据

线程本地数据是特定线程的数据。管理线程本地数据,只需要创建一个 local (或者一个子类型)的实例并在实例中储存属性:

mydata = threading.local()
mydata.x = 1

thread object

Thread 类代表在独立控制线程运行的活动。有两种方式指定活动:传递一个可调用对象给构造函数或者在子类重载 run() 方法。其它方法不应该在子类被(除了构造函数)重载。换句话说,只能 重载这个类的 init() 和 run() 方法。

当线程对象一旦被创建,其活动必须通过调用线程的 start() 方法开始。 这会在独立的控制线程中发起调用 run() 方法。

一旦线程活动开始,该线程会被认为是 ‘存活的’ 。当它的 run() 方法终结了(不管是正常的还是抛出未被处理的异常),就不是’存活的’。 is_alive() 方法用于检查线程是否存活。

其他线程可以调用一个线程的 join() 方法。这会阻塞调用该方法的线程,直到被调用 join() 方法的线程终结。

线程有名字。名字可以传递给构造函数,也可以通过 name 属性读取或者修改。

如果 run() 方法引发了异常,则会调用 threading.excepthook() 来处理它。 在默认情况下,threading.excepthook() 会静默地忽略 SystemExit。

一个线程可以被标记成一个“守护线程”。 这个标识的意义是,当剩下的线程都是守护线程时,整个 Python 程序将会退出。 初始值继承于创建线程。 这个标识可以通过 daemon 特征属性或者 daemon 构造器参数来设置。

属性和方法

start()

start()
开始线程活动。

它在一个线程里最多只能被调用一次。 它安排对象的 run() 方法在一个独立的控制线程中被调用。

如果同一个线程对象中调用这个方法的次数大于一次,会抛出 RuntimeError 。

run()

代表线程活动的方法。

你可以在子类型里重载这个方法。 标准的 run() 方法会对作为 target 参数传递给该对象构造器的可调用对象(如果存在)发起调用,并附带从 args 和 kwargs 参数分别获取的位置和关键字参数。

join()

等待,直到线程终结。这会阻塞调用这个方法的线程,直到被调用 join() 的线程终结 – 不管是正常终结还是抛出未处理异常 – 或者直到发生超时,超时选项是可选的。

当 timeout 参数存在而且不是 None 时,它应该是一个用于指定操作超时的以秒为单位的浮点数或者分数。因为 join() 总是返回 None ,所以你一定要在 join() 后调用 is_alive() 才能判断是否发生超时 – 如果线程仍然存活,则 join() 超时。

当 timeout 参数不存在或者是 None ,这个操作会阻塞直到线程终结。

如果尝试加入当前线程会导致死锁, join() 会引起 RuntimeError 异常。如果尝试 join() 一个尚未开始的线程,也会抛出相同的异常。

is_alive()

is_alive()
返回线程是否存活。

当 run() 方法刚开始直到 run() 方法刚结束,这个方法返回 True 。模块函数 enumerate() 返回包含所有存活线程的列表。

ident

线程启动后,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

native_id

这个是底层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开启的是真实的操作系统层面上的线程

name

# 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)

threading.active_count()

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)

threading.current_thread()

# 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()之前
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
运行完后处于stopped
在这里插入图片描述

在这里插入图片描述

lock

原始锁是一个在锁定时不属于特定线程的同步基元组件。在Python中,它是能用的最低级的同步基元组件,由 _thread 扩展模块直接实现。

原始锁处于 “锁定” 或者 “非锁定” 两种状态之一。它被创建时为非锁定状态。它有两个基本方法, acquire() 和 release() 。当状态为非锁定时, acquire() 将状态改为 锁定 并立即返回。当状态是锁定时, acquire() 将阻塞至其他线程调用 release() 将其改为非锁定状态,然后 acquire() 调用重置其为锁定状态并返回。 release() 只在锁定状态下调用; 它将状态改为非锁定并立即返回。如果尝试释放一个非锁定的锁,则会引发 RuntimeError 异常。

锁同样支持 上下文管理协议。

当多个线程在 acquire() 等待状态转变为未锁定被阻塞,然后 release() 重置状态为未锁定时,只有一个线程能继续执行;至于哪个等待线程继续执行没有定义,并且会根据实现而不同。

所有方法的执行都是原子性的。

acquire(blocking=True, timeout=- 1)

可以阻塞或非阻塞地获得锁。

当调用时参数 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上的信号中断锁的获取。

release()

释放一个锁。这个方法可以在任何线程中调用,不单指获得锁的线程。

当锁被锁定,将它重置为未锁定,并返回。如果其他线程正在等待这个锁解锁而被阻塞,只允许其中一个允许。

当在未锁定的锁上发起调用时,会引发 RuntimeError。

没有返回值。

locked()

当锁被获取时,返回 True。


based program language: python

thread线程

1.python主线程和子线程并发

切换的形式如下

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

2.python尽量用threading模块

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 理解

3.block sleep wait的区别:

实际上两者不用刻意区分两者,因为两者都会暂停线程的执行。

  • 两者的区别是:

    • 进入等待状态是线程主动的,而进入阻塞状态是被动的。
    • 更进一步的说,进入阻塞状态是在同步, 而进入等待状态是在同步代码之内。
    • 调用了sleep方法的线程直接受CPU调度,而wait则是等待另外的java线程在持有同一个对象锁的同步块,方法中进行notify调用。
  • 两者的共同点是:

    • 都暂时停止线程的执行,线程本身不会占用CPU时间片。

4.条件变量condition variable

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}')

5.线程简短的状态模型(非正式)

在这里插入图片描述

6.thread.Timer

作用是定时器后执行


# 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()

7.线程之间的数据分享

Three common approaches include:

  • Sharing a boolean variable with a threading.Event. 通过事件
  • Protecting shared data with a threading.Lock. 通过锁
  • Sharing data with a queue.Queue.通过队列

1.event事件

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...

2.lock

# 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
	...

3.queue

The queue module provides a number of queue types, such as:

  • Queue: A fully-featured first-in-first-out (FIFO) queue.
  • SimpleQueue: A FIFO queue with less functionality.
  • LifoQueue: A last-in-first-out (LIFO) queue.
  • PriorityQueue: A queue where the first items out are those with the highest priority.
# loop forever
while True:
# get an item of data from the queue
	data = queue.get()
# ...

8.shared变量种类

  • Local variables within a function.
  • Global variables defined in a script.
  • Instance variables defined in a class.

9.从线程返回数据

线程可以自己__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

10.Semaphore

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...
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万物琴弦光锥之外

给个0.1,恭喜老板发财

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值