python关于threading模块

1.简介

This module constructs higher-level threading interfaces on top of the lower level _thread module. See also the queue module

此模块在底层的_thread模块之上构建了更高层的线程接口
2.threading模块下的方法
(1) threading.active_count

threading.active_count()
Return the number of Thread objects currently alive. The returned count is equal to the length of the list returned by enumerate().

返回正在运行的线程对象的数量,效果等同于计算enumerate()列表的长度.

import threading
import time

def test1(x):
    print('test1-->{}'.format(x))
    time.sleep(3)
    print('test1 end')

def test2(x):
    print('test2-->{}'.format(x))
    time.sleep(5)
    print('test2 end{}'.format(x+1))


a = threading.Thread(target=test1, args=(5,))  # args必须iterable
b = threading.Thread(target=test2, args=(6,))

a.start()
b.start()

print(threading.active_count())
a.join()
print('ending')
print(threading.active_count())

#result
test1-->5
test2-->6
3  # active_count
test1 end
ending
2  # active_count
test2 end7

(2)

threading.current_thread()
Return the current Thread object, corresponding to the caller’s thread of control. If the caller’s thread of control was not created through the threading module, a dummy thread object with limited functionality is returned.

返回当前的线程对象,即是代码调用者的控制线程, 如果调用者的控制线程不是在threading模块中创建的, 那返回的将是一个被限制功能的线程对象.
注意当前线程不一定是主线程,而是调用程序的那个线程

def test1(x):
    print('test1-->{}'.format(x))
    time.sleep(3)
    print('test1 end')
    print(threading.current_thread())

a = threading.Thread(target=test1, args=(5,))
a.start()
print(threading.current_thread())
#
test1-->5
test1 end
<Thread(Thread-1, started 17656)>
<_MainThread(MainThread, started 11260)>

(3)threading.get_ident()

threading.get_ident()
Return the ‘thread identifier’ of the current thread. This is a nonzero integer. Its value has no direct meaning; it is intended as a magic cookie to be used e.g. to index a dictionary of thread-specific data. Thread identifiers may be recycled when a thread exits and another thread is created.

返回当前线程的线程标识符,是一个非零整数,并无直接意义; 可以神奇的用来索引关于线程数据的字典; 当一个线程结束时,这个数字可能被回收利用. ???

print(threading.get_ident())
#源码见第一个例子
18760

(4)threading.enumerate()

threading.enumerate()
Return a list of all Thread objects currently alive. The list includes daemonic threads, dummy thread objects created by current_thread(), and the main thread. It excludes terminated threads and threads that have not yet been started.

返回当前运行的线程对象的列表, 包括守护线程, current_thread方法创建的虚拟线程, 已及主线程. 不包括已结束的和未启动的线程.

a.start()
print(threading.enumerate())
b.start()
print(threading.enumerate())
a.join()
print('ending')
print(threading.enumerate())
print(threading.current_thread())
print(threading.get_ident())

#result
test1-->5
[<_MainThread(MainThread, started 1892)>, <Thread(Thread-1, started 3860)>]
test2-->6
[<_MainThread(MainThread, started 1892)>, <Thread(Thread-1, started 3860)>, <Thread(Thread-2, started 3108)>]
test1 end
ending
[<_MainThread(MainThread, started 1892)>, <Thread(Thread-2, started 3108)>]
<_MainThread(MainThread, started 1892)>
1892 # 每次运行都不一样就是因为线程结束后标识符会回收
test2 end7

(5)threading.main_thread()

threading.main_thread()
Return the main Thread object. In normal conditions, the main thread is the thread from which the Python interpreter was started.

返回主线程对象, 正常情况下, 主线程就是启动python解释器的线程.

a.start()
b.start()
print(threading.main_thread())
#result
test1-->5
test2-->6
<_MainThread(MainThread, started 19140)>

(6)

threading.settrace(func)
Set a trace function for all threads started from the threading module. The func will be passed to sys.settrace() for each thread, before its run() method is called.

threading.setprofile(func)
Set a profile function for all threads started from the threading module. The func will be passed to sys.setprofile() for each thread, before its run() method is called.

threading.stack_size([size]) 返回创建新线程时使用的堆栈大小
Return the thread stack size used when creating new threads. The optional size argument specifies the stack size to be used for subsequently created threads, and must be 0 (use platform or configured default) or a positive integer value of at least 32,768 (32 KiB). If size is not specified, 0 is used. If changing the thread stack size is unsupported, a RuntimeError is raised. If the specified stack size is invalid, a ValueError is raised and the stack size is unmodified. 32 KiB is currently the minimum supported stack size value to guarantee sufficient stack space for the interpreter itself. Note that some platforms may have particular restrictions on values for the stack size, such as requiring a minimum stack size > 32 KiB or requiring allocation in multiples of the system memory page size - platform documentation should be referred to for more information (4 KiB pages are common; using multiples of 4096 for the stack size is the suggested approach in the absence of more specific

才疏学浅, 上述3个待补充.

(7)threading.TIMEOUT_MAX

The maximum value allowed for the timeout parameter of blocking functions (Lock.acquire(), RLock.acquire(), Condition.wait(), etc.). Specifying a timeout greater than this value will raise an OverflowError.

返回阻塞函数的超时参数允许设定的最大值. 如果超过这个值会抛出异常

a.start()
print(threading.TIMEOUT_MAX)
b.start()
print(threading.TIMEOUT_MAX)

#result
test1-->5
4294967.0
test2-->6
4294967.0

3.模块说明

The design of this module is loosely based on Java’s threading model. However, where Java makes locks and condition variables basic behavior of every object, they are separate objects in Python. Python’s Thread class supports a subset of the behavior of Java’s Thread class; currently, there are no priorities, no thread groups, and threads cannot be destroyed, stopped, suspended, resumed, or interrupted. The static methods of Java’s Thread class, when implemented, are mapped to module-level functions.

大意是这个模块是参考Java的线程模块来的, 但不同于Java, 锁和条件变量在python中是独立的对象. 然鹅, python的线程类只是Java的子集, 没有优先级,没有线程组, 并且线程不可被销毁, 停止, 暂停, 恢复, 中断…
4.线程的局部数据

Thread-local data is data whose values are thread specific. To manage thread-local data, just create an instance of local (or a subclass) and store attributes on it:

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

The instance’s values will be different for separate threads.
class threading.local
A class that represents thread-local data.
For more details and extensive examples, see the documentation string of the _threading_local module.

利用local()方法或创建子类来创建线程的特有数据, 不同线程这些数据是不同的.
5. thread对象
5.1概述

The Thread class represents an activity that is run in a separate thread of control. There are two ways to specify the activity: by passing a callable object to the constructor, or by overriding the run() method in a subclass. No other methods (except for the constructor) should be overridden in a subclass. In other words, only override the __ init__() and run() methods of this class.

Thread类代表了一种在单独的控制线程中运行的活动. 这主要通过两种方式来实现: 将一个可调用对象传递给构造函数或者覆盖子类中的run()方法. 子类中的其他方法不应该被覆盖(除了构造函数), 换句话说, 只覆盖init()和run()方法.

Once a thread object is created, its activity must be started by calling the thread’s start() method. This invokes the run() method in a separate thread of control.

thread对象被创建后, 必须通过调用start()方法来启动他. 然后start就会在分离的线程中调用run()方法.

Once the thread’s activity is started, the thread is considered ‘alive’. It stops being alive when its run() method terminates – either normally, or by raising an unhandled exception. The is_alive() method tests whether the thread is alive.

一旦线程调用了start(), 那么他就是alive状态. 当run()方法终结后(无论是正常终结还是抛出异常),他又结束alive状态, 通过is_alive()来获取线程的状态.

Other threads can call a thread’s join() method. This blocks the calling thread until the thread whose join() method is called is terminated.

其他线程还可调用join()方法, 这会阻塞线程的调用, 直到调用join()的线程结束.

A thread has a name. The name can be passed to the constructor, and read or changed through the name attribute.

每个线程都有一个名字, 可通过构造函数指定, 也可通过name方法获取或更改.

A thread can be flagged as a “daemon thread”. The significance of this flag is that the entire Python program exits when only daemon threads are left. The initial value is inherited from the creating thread. The flag can be set through the daemon property or the daemon constructor argument.
Note:
Daemon threads are abruptly stopped at shutdown. Their resources (such as open files, database transactions, etc.) may not be released properly. If you want your threads to stop gracefully, make them non-daemonic and use a suitable signalling mechanism such as an Event.

线程可被标记为守护线程, 他的重要性在于python程序会在只剩守护线程时退出. 守护线程的初始值继承自创造他的线程, 并且可以通过构造函数或daemon方法设置.
注意:守护线程会在程序退出时突然终止, 他所调用的资源例如打开的文件,数据库等可能不能被正确的释放. 如果你想让守护线程正常退出, 请使用非守护线程并且使用信号机制例如event.

There is a “main thread” object; this corresponds to the initial thread of control in the Python program. It is not a daemon thread.
There is the possibility that “dummy thread objects” are created. These are thread objects corresponding to “alien threads”, which are threads of control started outside the threading module, such as directly from C code. Dummy thread objects have limited functionality; they are always considered alive and daemonic, and cannot be join()ed. They are never deleted, since it is impossible to detect the termination of alien threads.

还存在一个主线程对象, 即是python程序中的初始控制线程, 他并不是守护线程
另外关于虚拟线程, 是与外部线程有关的, 他启动于threading模块外部, 他只有限制的功能, 并且永远被视为运行状态和守护状态, 不可使用join()方法, 永远不会被删除, 因为不可能探测外部线程是否终结

示例: 用类继承的方法实现多线程

import threading

class Mythread(threading.Thread):
    def __init__(self):
        super().__init__(name='shit')
        self.shit = 233

    def run(self):
        print('hahahahah,{}'.format(self.shit))


a = Mythread()
a.start()
print(a)
#result
hahahahah,233
<Mythread(shit, started 12612)>

5.2 thread对象的方法
(1)构造函数
class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)

1)This constructor should always be called with keyword arguments. Arguments are:
2)group should be None; reserved for future extension when a ThreadGroup class is implemented.
3)target is the callable object to be invoked by the run() method. Defaults to None, meaning nothing is called.
4)name is the thread name. By default, a unique name is constructed of the form “Thread-N” where N is a small decimal number.
5)args is the argument tuple for the target invocation. Defaults to ().
6)kwargs is a dictionary of keyword arguments for the target invocation. Defaults to {}.
7)If not None, daemon explicitly sets whether the thread is daemonic. If None (the default), the daemonic property is inherited from the current thread.
8)If the subclass overrides the constructor, it must make sure to invoke the base class constructor (Thread.__ init__()) before doing anything else to the thread.

构造函数传入的参数应该都是关键字参数;
group参数永远是None, 留待未来扩展功能;
target参数应该是可调用的对象, 他后续会被run()方法调用,默认为None;
name参数指定线程的名字,默认会指定Thread-N的名字形式;
args参数传入一个元组或iterable,取出每个元素作为target的参数
kwargs参数传入一个字典,取出键值对作为target的关键字参数
daemon参数如果指定, 那就会显性的设定是否为守护线程,如果为None,则从创建他的线程中继承;

如果该类的子类要覆盖构造函数, 那确保会激发基类Thread的__ init__方法.
示例:

a = threading.Thread(target=test1, name='fuck', args=(5,6,7), daemon=True)  # args须为iterable

a.start()
print(a)
#result
test1-->567
<Thread(fuck, started daemon 10200)>

(2)start()

start()
Start the thread’s activity.
It must be called at most once per thread object. It arranges for the object’s run() method to be invoked in a separate thread of control.
This method will raise a RuntimeError if called more than once on the same thread object.

启动线程, 最多只能调用一次(因为run()方法执行后会删除对象的target属性和args属性),由他来调用对象的run()方法,
(3)run()

Method representing the thread’s activity.
You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.

表示线程活动的方法, 调用构造函数中的target函数和args, kwargs参数

    def run(self):  # run方法源码
        try:
            if self._target:
                self._target(*self._args, **self._kwargs)
        finally:
            # Avoid a refcycle if the thread is running a function with
            # an argument that has a member that points to the thread.
            del self._target, self._args, self._kwargs

(4)join(timeout=None)

1)Wait until the thread terminates. This blocks the calling thread until the thread whose join() method is called terminates – either normally or through an unhandled exception – or until the optional timeout occurs.
2)When the timeout argument is present and not None, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof). As join() always returns None, you must call is_alive() after join() to decide whether a timeout happened – if the thread is still alive, the join() call timed out.
3)When the timeout argument is not present or None, the operation will block until the thread terminates.
4)A thread can be join()ed many times.
5)join() raises a RuntimeError if an attempt is made to join the current thread as that would cause a deadlock. It is also an error to join() a thread before it has been started and attempts to do so raise the same exception.

等待直到线程终止(正常或非正常终止或发生超时);

当timeout参数不为None时, 它应该是一个浮点数,来表明操作超时的秒数,因为join总是return True, 你只能通过调用is_alive方法来判断它是否发生超时, 如果线程仍然是alive, 那超时发生了;

如果timeout参数是None, 那阻塞直到线程结束;

一个线程可以join多次;

如果试图给当前线程使用join会导致死锁; 在线程启动前join也会发生同样的异常;

import threading
import time

def test1(x, y, z):
    print('test1-->{}{}{}'.format(x, y, z))
    time.sleep(5)
    print('test1 end')
    print(threading.current_thread())

def test2(x):
    print('test2-->{}'.format(x))
    time.sleep(5)
    print('test2 end{}'.format(x+1))


a = threading.Thread(target=test1, name='fuck', args='abc', daemon=True)  # args必须iterable
b = threading.Thread(target=test2, args=(6,))

a.start()
print(a)
a.join(2)
print(a.is_alive())
b.start()
a.join()  # 第二次join
print('ending')

#result
test1-->abc
<Thread(fuck, started daemon 1812)>
True  # 说明超时被调用
test2-->6
test1 end 
<Thread(fuck, started daemon 1812)>
ending 
test2 end7

(5)name

A string used for identification purposes only. It has no semantics. Multiple threads may be given the same name. The initial name is set by the constructor.

线程名字符串,仅作为标识, 不同线程可能有相同的名字; 初始名字在构造函数中设置;

getName()
setName()
老的set和get方法

实例:

#还是上边的源码
a.start()
print(a)
a.name = 'shit'
print(a.name)
b.start()
b.name = 'shit' # 设置相同的名字
print(b)
a.join()
print('ending')
a.setName('happy')  # 老方法
print(a.getName(), b.getName())

#result
test1-->abc
<Thread(fuck, started 10476)>
shit
test2-->6
<Thread(shit, started 1332)>
test2 end7
test1 end
<Thread(shit, started 10476)>
happy shit
ending

(6)ident

The ‘thread identifier’ of this thread or None if the thread has not been started. This is a nonzero integer. See the get_ident() function. Thread identifiers may be recycled when a thread exits and another thread is created. The identifier is available even after the thread has exited.

返回线程的identifier或None(如果线程还没start), 是一个非零整数. identifier在线程退出并且另一个线程被创建时可能被回收重用, identifier在线程退出后仍然可以访问

(7)is_alive()

Return whether the thread is alive.
This method returns True just before the run() method starts until just after the run() method terminates. The module function enumerate() returns a list of all alive threads.

判断线程是否alive并返回布尔值;

示例(6)(7)

a.start()
print(a.is_alive())
print(a.ident)
print(a)
print(b.ident)
b.start()
print(b)
a.join()
print('ending')
print(a.ident)

#result
test1-->abc
True
4688
<Thread(fuck, started 4688)>
None  # 线程未启动时identifier为None
test2-->6
<Thread(Thread-1, started 12272)>
test1 end
<Thread(fuck, started 4688)>
ending
4688  # 线程结束后仍可调用
test2 end7

(8)daemon

A boolean value indicating whether this thread is a daemon thread (True) or not (False). This must be set before start() is called, otherwise RuntimeError is raised. Its initial value is inherited from the creating thread; the main thread is not a daemon thread and therefore all threads created in the main thread default to daemon = False.
The entire Python program exits when no alive non-daemon threads are left.

返回一个布尔值, 判断线程是否为守护线程, 注意必须在start()前设置; 如不设置它的初始值从创建它的线程中继承; 由于主线程不是守护线程, 所以所有在主线程中创建的线程默认都不是守护线程

整个python程序会退出如果没有非守护线程遗留的话.

isDaemon()
setDaemon()
老方法

#源码仍为上例
a.daemon = True
a.start()
print(a)
print(a.daemon)
print(b.isDaemon()) 老方法
b.setDaemon(True)
a.join()
b.start()
print(b)
print('ending')
print(a.ident)

#result
test1-->abc
<Thread(fuck, started daemon 17780)>
True
False
test1 end
<Thread(fuck, started daemon 17780)>
test2-->6
<Thread(Thread-1, started daemon 16812)>
ending
17780

6. lock对象

A primitive lock is a synchronization primitive that is not owned by a particular thread when locked. In Python, it is currently the lowest level synchronization primitive available, implemented directly by the _thread extension module.

原始锁, 锁定时不属于任何特定线程, 在python中它是目前可使用的最低级别的同步原语, 直接被_thread扩展模块实现.

A primitive lock is in one of two states, “locked” or “unlocked”. It is created in the unlocked state. It has two basic methods, acquire() and release(). When the state is unlocked, acquire() changes the state to locked and returns immediately. When the state is locked, acquire() blocks until a call to release() in another thread changes it to unlocked, then the acquire() call resets it to locked and returns. The release() method should only be called in the locked state; it changes the state to unlocked and returns immediately. If an attempt is made to release an unlocked lock, a RuntimeError will be raised.

原始锁有两种状态, 锁定或非锁定; 在锁创建时为非锁定状态; 当为非锁定状态时, acquire()方法使其转变为锁定状态并且立即返回; 当处于锁定状态时, acquire()方法会被阻塞直到另一个线程调用release()方法来给它解锁, 然后acquire会把锁重设为锁定状态并返回. release()方法只能在锁定状态下调用, 否则会抛出异常,它把状态改为非锁定并立即返回.

When more than one thread is blocked in acquire() waiting for the state to turn to unlocked, only one thread proceeds when a release() call resets the state to unlocked; which one of the waiting threads proceeds is not defined, and may vary across implementations.

当不止一个线程被acquire阻塞等待状态解锁, 那么当解锁时只有一个线程会继续执行, 至于哪个线程继续执行是未定义的,并且可能因实现方法而异;
注意:锁不阻塞线程, 而是阻塞没有获取到锁的线程

6.2 lock对象的方法

class threading.Lock
The class implementing primitive lock objects. Once a thread has acquired a lock, subsequent attempts to acquire it block, until it is released; any thread may release it.
Note that Lock is actually a factory function which returns an instance of the most efficient version of the concrete Lock class that is supported by the platform.

threading类来实现原始锁对象; 一旦某个线程获得锁, 那后续获取锁的行为会阻塞, 直到锁被release; 任何线程都可能release它;
注意:锁其实是个工厂函数, 它返回平台支持的最高效版本的Lock类的实例.
(1)acquire(blocking=True, timeout=-1)

1)Acquire a lock, blocking or non-blocking.
2)When invoked with the blocking argument set to True (the default), block until the lock is unlocked, then set it to locked and return True.
3)When invoked with the blocking argument set to False, do not block. If a call with blocking set to True would block, return False immediately; otherwise, set the lock to locked and return True.
4)When invoked with the floating-point timeout argument set to a positive value, block for at most the number of seconds specified by timeout and as long as the lock cannot be acquired. A timeout argument of -1 specifies an unbounded wait. It is forbidden to specify a timeout when blocking is false.
5)The return value is True if the lock is acquired successfully, False if not (for example if the timeout expired).

获取一个锁, 阻塞或非阻塞.
当blocking参数设为Ture时, 该语句会一直阻塞直到锁设置为unlock状态,然后立即返回True并把锁设为lock状态.
当blocking参数设为False时, 不会被阻塞, 返回值会有差异: 当在lock状态下时返回False, 其他状态下将锁设为lock状态并返回True

timeout参数是个浮点数, 在没有获取lock的状态下, 阻塞最多不超过指定的时间; 默认参数-1无等待限制; 另外, 在blocking参数为False时禁止该参数

获取lock时返回True, 没有获取或超时返回False.

(2)release()

Release a lock. This can be called from any thread, not only the thread which has acquired the lock.
When the lock is locked, reset it to unlocked, and return. If any other threads are blocked waiting for the lock to become unlocked, allow exactly one of them to proceed.
When invoked on an unlocked lock, a RuntimeError is raised.

释放lock; 这个方法可在任何线程中调用, 而不局限于获取锁的线程;
当lock处于锁定状态时,把它变为非锁定状态,并且返回(None); 解锁后只有一个等待的线程可以继续;
用于非锁定状态的锁会抛出异常;

示例:

def test1():
    print(l.acquire())
    print('test1 starting')
    time.sleep(5)
    print('test1 ending')


def test2():
    print(l.acquire(blocking=False)) # 并不会被阻塞并返回False
    print('test2 starting')
    time.sleep(4)
    print('test2 ending')


def test3():
    print(l.acquire(timeout=2))  # 超时返回False并取消阻塞
    print('test3 starting')
    time.sleep(2)
    print(l.release())  #  在任意线程release, 返回None
    print('test3 ending')


def test4():
    print(l.acquire())
    print('test4 starting')
    time.sleep(3)
    print('test4 ending')


a = threading.Thread(target=test1)
b = threading.Thread(target=test2)
c = threading.Thread(target=test3)
d = threading.Thread(target=test4)

l = threading.Lock()

a.start()
b.start()
c.start()
d.start()
print(l.locked())

print('main ending')

#result
True
test1 starting
False
test2 starting
True
main ending
False
test3 starting
None
True
test4 starting
test2 ending
test3 ending
test1 ending
test4 ending

7. Rlock对象
7.1概述

1)A reentrant lock is a synchronization primitive that may be acquired multiple times by the same thread. Internally, it uses the concepts of “owning thread” and “recursion level” in addition to the locked/unlocked state used by primitive locks. In the locked state, some thread owns the lock; in the unlocked state, no thread owns it.
2)To lock the lock, a thread calls its acquire() method; this returns once the thread owns the lock. To unlock the lock, a thread calls its release() method. acquire()/release() call pairs may be nested; only the final release() (the release() of the outermost pair) resets the lock to unlocked and allows another thread blocked in acquire() to proceed.

可重用锁是可被同一个线程重复获取的, 在内部,除了lock和unlock状态外还使用了归属线程和递归级别的概念. 在Lock状态, 它属于某个线程, 而在unlock状态, 它不属于任何线程;
线程调用acquire()来将锁变为锁定状态, 一旦线程拥有锁就会返回; 调用release()来将锁解锁; acquire和release成对调用并可能嵌套;但只有最外面的release才会将锁解锁并允许其他线程来获取它.

**6.2 Rlock类的方法
(1)class threading.RLock

This class implements reentrant lock objects. A reentrant lock must be released by the thread that acquired it. Once a thread has acquired a reentrant lock, the same thread may acquire it again without blocking; the thread must release it once for each time it has acquired it.
Note that RLock is actually a factory function which returns an instance of the most efficient version of the concrete RLock class that is supported by the platform.

用这个类来实现可重用锁; **可重用锁必须由获取它的线程来解锁, 一旦某个线程获取了锁, 那这个线程可以在无阻塞的情况下重复获取它;**线程每次acquire必须有一个release和它一 一对应.

(2)acquire(blocking=True, timeout=-1)

1)Acquire a lock, blocking or non-blocking.
2)When invoked without arguments: if this thread already owns the lock, increment the recursion level by one, and return immediately. Otherwise, if another thread owns the lock, block until the lock is unlocked. Once the lock is unlocked (not owned by any thread), then grab ownership, set the recursion level to one, and return. If more than one thread is blocked waiting until the lock is unlocked, only one at a time will be able to grab ownership of the lock. There is no return value in this case.
3)When invoked with the blocking argument set to true, do the same thing as when called without arguments, and return true.
4)When invoked with the blocking argument set to false, do not block. If a call without an argument would block, return false immediately; otherwise, do the same thing as when called without arguments, and return true.
5)When invoked with the floating-point timeout argument set to a positive value, block for at most the number of seconds specified by timeout and as long as the lock cannot be acquired. Return true if the lock has been acquired, false if the timeout has elapsed.

acquire方法获取锁, 产生阻塞或非阻塞
当在没有参数的情况下调用时,如果该线程已经获取了锁, 那递归等级加一并立即返回; 否则如果其他线程获取锁, 那么阻塞直到锁解锁. 锁解锁后, 如果获取到所有权, 那就递归等级变为1并且立即返回; 如果不止一个线程在等待解锁, 那解锁后只能有一个线程可获得所有权,这种情况下无返回值;

当blocking参数为True时, 和上述没有参数的情况相同,并返回True;

当blocking参数为False时, 不会阻塞; 当锁处于锁定状态时返回False,否则返回True;

timeout参数为正的浮点数, 在没有获取锁的情况下, 阻塞最多不超过相应的秒数, timeout发生后返回False;

(3)release()

Release a lock, decrementing the recursion level. If after the decrement it is zero, reset the lock to unlocked (not owned by any thread), and if any other threads are blocked waiting for the lock to become unlocked, allow exactly one of them to proceed. If after the decrement the recursion level is still nonzero, the lock remains locked and owned by the calling thread.
Only call this method when the calling thread owns the lock. A RuntimeError is raised if this method is called when the lock is unlocked.
There is no return value.

该方法解锁,并把递归等级减一, 如果递归等级减为0, 那锁变为非锁定状态, 并且如果不止一个线程在等待非锁定状态, 那只有其中一个线程可以继续, 如果递归等级减少后仍不为0, 那仍为锁定状态并且归该线程所有;
只有拥有锁的线程才能调用此方法, 如果尝试释放非锁定状态的锁将抛出异常;

import threading
import time


def test1():
    print(l.acquire())
    print('test1 starting')
    time.sleep(3)
    print(l.acquire())  # 递归获取锁
    print('test1 running')
    l.release()
    print('test1 ending')
    print(l.release())  # 只能自己释放


def test2():
    print(l.acquire(blocking=False))  # lock状态下返回False
    print('test2 starting')
    time.sleep(4)
    print('test2 ending')


def test3():
    print(l.acquire(timeout=2)) # 超时返回False
    print('test3 starting')
    time.sleep(2)
    print('test3 ending')


def test4():
    print(l.acquire())  # lock状态下一直阻塞
    print('test4 starting')
    time.sleep(3)
    print('test4 ending')


a = threading.Thread(target=test1)
b = threading.Thread(target=test2)
c = threading.Thread(target=test3)
d = threading.Thread(target=test4)

l = threading.RLock()

a.start()
b.start()
c.start()
d.start()

print('main ending')

#result
True
test1 starting
False
test2 starting
main ending
False
test3 starting
True
test1 running
test1 ending
None
True
test4 starting
test3 ending
test2 ending
test4 ending

7. semaphore对象
7.1 概述

This is one of the oldest synchronization primitives in the history of computer science, invented by the early Dutch computer scientist Edsger W. Dijkstra (he used the names P() and V() instead of acquire() and release()).
A semaphore manages an internal counter which is decremented by each acquire() call and incremented by each release() call. The counter can never go below zero; when acquire() finds that it is zero, it blocks, waiting until some other thread calls release().

计算机科学史上最古老的同步原语之一, 被荷兰科学家发明;
信号锁内部管理着一个计数器, 每调用一次acquire减一, 每调用一次release加一; 计数器永不可能小于0, 如果它等于0, acquire将被阻塞, 直到别的线程调用release方法.

**7.2 semaphore对象
(1)class threading.Semaphore(value=1)

This class implements semaphore objects. A semaphore manages an atomic counter representing the number of release() calls minus the number of acquire() calls, plus an initial value. The acquire() method blocks if necessary until it can return without making the counter negative. If not given, value defaults to 1.
The optional argument gives the initial value for the internal counter; it defaults to 1. If the value given is less than 0, ValueError is raised.

这个类来实现semaphore对象, 它管理着一个自动计数器,表示release的次数减去acquire的次数, 再加上初始值; acquire会被阻塞,直到它能在不使计数器变为负数的情况下返回; 如果没有设定, 初始值为1; 如果设定小于0 ,则抛出异常;

(2)acquire(blocking=True, timeout=None)

Acquire a semaphore.
When invoked without arguments:
•If the internal counter is larger than zero on entry, decrement it by one and return true immediately.
•If the internal counter is zero on entry, block until awoken by a call to release(). Once awoken (and the counter is greater than 0), decrement the counter by 1 and return true. Exactly one thread will be awoken by each call to release(). The order in which threads are awoken should not be relied on.
2)When invoked with blocking set to false, do not block. If a call without an argument would block, return false immediately; otherwise, do the same thing as when called without arguments, and return true.
3)When invoked with a timeout other than None, it will block for at most timeout seconds. If acquire does not complete successfully in that interval, return false. Return true otherwise.

当在无参数的情况下调用时, 如果内部计数器大于0, 那把它减一并立即返回True; 如果计数器等于0, 阻塞直到被release唤醒; 一个release只能唤醒一个线程, 至于是哪个线程, 则未知;

如果blocking参数为Falese, 那不会阻塞, 如果semaphore是锁定状态, 返回False; 否则返回Ture;

timeout参数会阻塞最多相应的秒数,触发timeout会返回False;

(3)release()

Release a semaphore, incrementing the internal counter by one. When it was zero on entry and another thread is waiting for it to become larger than zero again, wake up that thread.

使内部计数器加一; 当计数器是0时, 唤醒一个线程;

(4)class threading.BoundedSemaphore(value=1)

Class implementing bounded semaphore objects. A bounded semaphore checks to make sure its current value doesn’t exceed its initial value. If it does, ValueError is raised. In most situations semaphores are used to guard resources with limited capacity. If the semaphore is released too many times it’s a sign of a bug. If not given, value defaults to 1.

这个类实现有界信号量对象. 有界信号量会检查并确保目前的线程数不超过设定值, 否则会抛出异常; 这种对象大多数情况下用于保护容量有限的资源; 如果信号量被释放太多次, 表明程序有bug.

示例:

import threading
import time


def test1():
    print(l.acquire())
    print('test1 starting')
    print('test1 running')
    print('test1 ending')


def test2():
    print(l.acquire())  # 只能同时acquire两个
    print('test2 starting')
    time.sleep(4)
    print('test2 ending')


def test3():
    print(l.acquire(timeout=2)) # 超时返回False
    print('test3 starting')
    time.sleep(2)
    print(l.release())  # 可在任意位置release, 次数不限,release越多,可同时进行的线程越多
    print('test3 ending')


def test4():
    print(l.acquire())
    print('test4 starting')
    time.sleep(3)
    print('test4 ending')


a = threading.Thread(target=test1)
b = threading.Thread(target=test2)
c = threading.Thread(target=test3)
d = threading.Thread(target=test4)

l = threading.Semaphore(2) #如果是Boundsemephore, release过多会异常

a.start()
b.start()
c.start()
d.start()

print('main ending')

#result
True
test1 starting
test1 running
test1 ending
True
test2 starting
main ending
False
test3 starting
test2 ending
None
test3 ending
True
test4 starting
test4 ending

**8.event对象
8.1概述

This is one of the simplest mechanisms for communication between threads: one thread signals an event and other threads wait for it.
An event object manages an internal flag that can be set to true with the set() method and reset to false with the clear() method. The wait() method blocks until the flag is true.

这是线程间通信最简单的方式之一; event对象管理一个内部标记, 这个标记可被set()方法设为True, clear()方法设为False. wait()方法会一直阻塞直到标记设为True;

8.2event对象
(1)class threading.Event

Class implementing event objects. An event manages a flag that can be set to true with the set() method and reset to false with the clear() method. The wait() method blocks until the flag is true. The flag is initially false.

flag初始默认为False

(2)is_set()

Return true if and only if the internal flag is true.

检查flag是否为True

(3)set()

Set the internal flag to true. All threads waiting for it to become true are awakened. Threads that call wait() once the flag is true will not block at all

将flag设为True. 所有等待的线程将被唤醒;在flag为True的情况下调用wait()方法将不会阻塞;

(4)clear()

Reset the internal flag to false. Subsequently, threads calling wait() will block until set() is called to set the internal flag to true again.

重设flag为false. 之后调用wait()方法将被阻塞

(5)wait(timeout=None)

1)Block until the internal flag is true. If the internal flag is true on entry, return immediately. Otherwise, block until another thread calls set() to set the flag to true, or until the optional timeout occurs.
2)When the timeout argument is present and not None, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof).
3)This method returns true if and only if the internal flag has been set to true, either before the wait call or after the wait starts, so it will always return True except if a timeout is given and the operation times out.
Changed in version 3.1: Previously, the method always returned None.

阻塞直到flag为true或超时发生;
当且仅当flag为True时返回True; 无论在wait()调用前或调用后;

示例:

import threading
import time


def test1():
    print(l.wait())
    print('test1 starting')
    print(l.clear())
    print('test1 running')
    print(l1.set())
    print('test1 ending')


def test2():
    time.sleep(2)
    print(l.wait())
    print('test2 starting')
    print('test2 ending')


def test3():
    print(l1.wait(2))
    print('test3 starting')
    time.sleep(2)
    print(l.set())
    print('test3 ending')


def test4():
    print(l.set())
    print('test4 starting')
    time.sleep(3)
    print('test4 ending')


a = threading.Thread(target=test1)
b = threading.Thread(target=test2)
c = threading.Thread(target=test3)
d = threading.Thread(target=test4)

l = threading.Event()
l1 = threading.Event()

a.start()
b.start()
c.start()
d.start()

print('main ending')

#result
None
main ending
True
test1 starting
None
test4 starting
test1 running
None
test1 ending
True
test3 starting
None
test3 ending
test4 ending
True
test2 starting
test2 ending

9. condition对象
可通过绑定一个锁, 然后调用wait()让获取锁的线程暂时挂起,然后锁可被其他线程获取, 直到其他线程调用notify(), 该线程重新获取锁并继续执行.
**待补充

10. timer对象

This class represents an action that should be run only after a certain amount of time has passed — a timer. Timer is a subclass of Thread and as such also functions as an example of creating custom threads.
Timers are started, as with threads, by calling their start() method. The timer can be stopped (before its action has begun) by calling the cancel() method. The interval the timer will wait before executing its action may not be exactly the same as the interval specified by the user.

计时器:等待一段时间后执行

**待补充

11 barrier对象

This class provides a simple synchronization primitive for use by a fixed number of threads that need to wait for each other. Each of the threads tries to pass the barrier by calling the wait() method and will block until all of the threads have made their wait() calls. At this point, the threads are released simultaneously.
The barrier can be reused any number of times for the same number of threads.

阻塞直到所有线程都调用了wait()方法

示例:

import threading
import time


def test1():
    print(l1.acquire())
    print('test1 starting')
    print('test1 running')
    print(l1.wait())
    print('test1 ending')


def test2():
    time.sleep(1)
    l1.acquire()
    print('test2 starting')
    print('test2 ending')
    print(l1.notify())
    l1.release()

a = threading.Thread(target=test1)
b = threading.Thread(target=test2)

l = threading.Lock()
l1 = threading.Condition(l)

a.start()
b.start()
print('main ending')

#result
True
test1 starting
test1 running
main ending
test2 starting
test2 ending
None
True
test1 ending

**待补充

12 .调用上下文管理协议

All of the objects provided by this module that have acquire() and release() methods can be used as context managers for a with statement. The acquire() method will be called when the block is entered, and release() will be called when the block is exited. Hence, the following snippet:

所有上诉提到的有acquire和release方法的对象都可以使用with语句来管理; 例如:

with some_lock:
    # do something...

#is equivalent to:

some_lock.acquire()
try:
    # do something...
finally:
    some_lock.release()
    
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值