This article mainly introduces the Python thread, this article explains all aspects of threading knowledge, such as thread basic knowledge thread state, thread synchronization (lock), thread communication (condition variable) and so on, need friends can refer to the following
1. Thread Basics
1.1. Thread state
The thread has 5 states, and the process of state conversion is shown in the following illustration:
1.2. Thread Sync (lock)
The advantage of multithreading is that you can run multiple tasks at the same time (at least it feels that way). However, when a thread needs to share data, there may be a problem with data synchronization. Consider a situation where all elements in a list are 0, and the thread "set" changes all elements from the back to 1, while thread "print" is responsible for reading the list and printing it backwards. Then, when the thread "set" starts to change, the thread "print" Prints the list, and the output becomes half 01 and a 1, which is the data's different steps. In order to avoid this situation, the concept of lock is introduced.
There are two states of a lock-locked and unlocked. Whenever a thread such as "set" wants to access the shared data, the lock must first be obtained, and if there are other threads such as "print" that are locked, then the thread "set" is paused, which means the synchronization is blocked, and the thread "set" continues after the thread "print" is accessed and the lock is released. After this processing, the print list is either full output 0, or all output 1, no more than half 1 and a half 1 embarrassing scene.
The interaction between threads and locks is shown in the following illustration:
1.3. Thread communication (condition variable)
Yet there is another awkward situation: The list is not in the beginning; it is created by thread "create." An exception occurs if "set" or "print" accesses the list when "create" is not running. Using locks solves this problem, but "set" and "print" will require an infinite loop-they do not know when "create" will run, let "create" after running to notify "set" and "print" is clearly a better solution. Then, the conditional variable is introduced.
A condition variable allows threads such as "set" and "print" to wait when the condition is not satisfied (the list is none). Wait until the condition is satisfied (the list has been created) to send a notice telling the "set" and "print" conditions are already available, you should get up and work; then the "Set" and " Print "continues to run.
The interaction between a thread and a condition variable is shown in the following illustration:
1.4. Thread running and blocking state transitions
Finally, take a look at the transition of thread running and blocking state.
There are three types of blocking:
Synchronous blocking refers to the state of competitive locking, when the thread requests the lock, it will enter this state, once the lock has been successfully restored to the running state;
Wait for blocking refers to waiting for other threads to notify the state, the thread gets the condition lock, call "Wait" will enter this state, once the other threads give notice, the thread will enter the synchronized blocking state, again competitive condition lock;
Other blocking refers to blocking when calling Time.sleep (), Anotherthread.join (), or waiting for IO, which does not release the acquired lock.
Tips: If you can understand the content, the next topic will be very easy, and the content is the same in most popular programming languages. (meaning is to understand not to >_< too low author level to find someone else's tutorial to understand)
2. Thread
Python provides thread support through two standard library thread and threading. Thread provides low-level, raw threads, and a simple lock.
The code is as follows:
# Encoding:utf-8
Import Thread
Import time
# a function to be executed in a thread
def func ():
For I in range (5):
print ' func '
Time.sleep (1)
# End Current Thread
# This method is equivalent to Thread.exit_thread ()
Thread.exit () # When Func returns, the thread will also end
# Start a thread, the thread starts running immediately
# This method is equivalent to Thread.start_new_thread ()
# The first parameter is the method, and the second parameter is the parameter of the method
Thread.start_new (func, ()) # method requires incoming NULL when no parameters are available tuple
# Create a lock (LockType, not directly instantiated)
# This method is equivalent to Thread.allocate_lock ()
Lock = Thread.allocate ()
# to determine whether the lock is locked or released
Print lock.locked ()
# locks are typically used to control access to shared resources
Count = 0
# Acquire Lock, return true after successful lock acquisition
# Optional Timeout parameter will block until lock is not filled
# Otherwise the timeout will return false
If Lock.acquire ():
Count + 1
# release Lock
Lock.release ()
# The threads provided by the thread module will end at the same time as the main thread ends
Time.sleep (6)
Other methods provided by the thread module:
Thread.interrupt_main (): Terminates the main thread in other threads.
Thread.get_ident (): Gets a magic number representing the current thread, often used to get thread-related data from a dictionary. The number itself has no meaning and will be reused by the new thread when the thread is finished.
Thread also provides a threadlocal class for managing thread-related data, which is referenced in the name thread._local,threading.
Because thread provides a few threads, it is not possible to continue running after the main thread is finished, not to provide conditional variables and so on, the thread module is generally not used, here is not more.
3. Threading
Threading Java-based threading model design. Locks (lock) and condition variables (Condition) are the basic behavior of objects in Java (each object has its own lock and condition variable), while in Python it is a separate object. Python thread provides a subset of the behavior of Java thread; There is no priority, thread group, and thread cannot be stopped, paused, recovered, interrupted. Some of the Java thread's static methods implemented in Python are provided in the form of modular methods in threading.
The common methods provided by the threading module are:
Threading.currentthread (): Returns the current thread variable.
Threading.enumerate (): Returns a list containing the running thread. Running refers to threads that start and end after the thread has started, not including before and after the start.
Threading.activecount (): Returns the number of threads running, with the same result as Len (Threading.enumerate ()).
Classes provided by the threading module:
Thread, Lock, Rlock, Condition, [Bounded]semaphore, Event, Timer, Local.
3.1. Thread
Thread is a threading class, similar to Java, with two ways of using it, passing directly to the method to run or inheriting from thread and overwriting run ():
The code is as follows:
# Encoding:utf-8
Import threading
# method 1: The method to be executed is passed as a parameter to the thread construction method
def func ():
print ' func () passed to Thread '
t = Threading. Thread (Target=func)
T.start ()
# Method 2: Inherit from thread, and rewrite run ()
Class Mythread (threading. Thread):
def run (self):
print ' Mythread extended from Thread '
t = Mythread ()
T.start ()
Construction Method:
Thread (Group=none, Target=none, Name=none, args= (), kwargs={})
Group: Thread Group, currently not implemented, the library reference must be a hint of none;
Target: The method to be executed;
Name: thread name;
Args/kwargs: The arguments to pass in the method.
Instance method:
IsAlive (): Returns whether the thread is running. Running refers to the start, before termination.
Get/setname (name): Gets/sets the thread name.
Is/setdaemon (BOOL): Gets/Sets whether the daemon is a thread. The initial value is inherited from the thread that created the thread. When no non-daemon thread is still running, the program terminates.
Start (): Start the thread.
Join ([timeout]): The thread that blocks the current context environment until the thread calling this method terminates or arrives at the specified timeout (optional parameter).
An example of using join ():
The code is as follows:
# Encoding:utf-8
Import threading
Import time
def context (Tjoin):
print ' in Threadcontext. '
Tjoin.start ()
# will block Tcontext until Threadjoin terminates.
Tjoin.join ()
# Tjoin continues execution after termination.
print ' Out Threadcontext. '
def join ():
print ' in Threadjoin. '
Time.sleep (1)
print ' Out threadjoin. '
Tjoin = Threading. Thread (Target=join)
Tcontext = Threading. Thread (Target=context, args= (Tjoin,))
Tcontext.start ()
Run Result:
The code is as follows:
In Threadcontext.
In Threadjoin.
Out Threadjoin.
Out Threadcontext.
3.2. Lock
Lock (Instruction Lock) is the lowest level of synchronization instruction available. When lock is locked, it is not owned by a particular thread. Lock contains two states-locking and non-locking, and two basic methods.
You can think that lock has a lock pool, and when a thread requests a lock, the thread is in the pool until it gets locked out of the pool. The threads in the pool are in a synchronized blocking state in the Statechart diagram.
Construction Method:
Lock ()
Instance method:
Acquire ([timeout]): Causes the thread to enter a synchronized blocking state, attempting to acquire a lock.
Release (): Releases the lock. The use of a thread must have been locked or an exception will be thrown.
The code is as follows:
# Encoding:utf-8
Import threading
Import time
data = 0
Lock = Threading. Lock ()
def func ():
Global Data
print '%s acquire lock ... '% threading.currentthread (). GetName ()
# when calling acquire ([timeout]), the thread will always block,
# until the lock is obtained or until timeout seconds (timeout parameter optional).
# returns whether a lock is obtained.
If Lock.acquire ():
print '%s get the lock. '% Threading.currentthread (). GetName ()
Data + + 1
Time.sleep (2)
Print '%s release lock ... '% threading.currentthread (). GetName ()
# calling release () releases the lock.
Lock.release ()
T1 = Threading. Thread (Target=func)
T2 = Threading. Thread (Target=func)
T3 = Threading. Thread (Target=func)
T1.start ()
T2.start ()
T3.start ()
3.3. Rlock
A rlock (Reentrant lock) is a synchronization instruction that can be requested multiple times by the same thread. Rlock uses the concept of "owning threads" and "recursive Rank", and Rlock is owned by a thread while in a locked state. The thread that owns the Rlock can call acquire () again, and the same number of releases () will be invoked when the lock is released.
It can be considered that rlock contains a lock pool and a counter with an initial value of 0, each time the acquire ()/release () is successfully invoked, the counter is +1/-1, and the lock is unlocked for 0 o'clock.
Construction Method:
Rlock ()
Instance method:
Acquire ([timeout])/release (): Similar to lock.
The code is as follows:
# Encoding:utf-8
Import threading
Import time
Rlock = Threading. Rlock ()
def func ():
# The first time you request a lock
print '%s acquire lock ... '% threading.currentthread (). GetName ()
If Rlock.acquire ():
print '%s get the lock. '% Threading.currentthread (). GetName ()
Time.sleep (2)
# Second Request lock
print '%s acquire lock again ... '% threading.currentthread (). GetName ()
If Rlock.acquire ():
print '%s get the lock. '% Threading.currentthread (). GetName ()
Time.sleep (2)
# Unlock the locks for the first time
Print '%s release lock ... '% threading.currentthread (). GetName ()
Rlock.release ()
Time.sleep (2)
# Second Release lock
Print '%s release lock ... '% threading.currentthread (). GetName ()
Rlock.release ()
T1 = Threading. Thread (Target=func)
T2 = Threading. Thread (Target=func)
T3 = Threading. Thread (Target=func)
T1.start ()
T2.start ()
T3.start ()
3.4. Condition
Condition (condition variable) is usually associated with a lock. When you need to share a lock in multiple contidion, you can pass a Lock/rlock instance to the construction method, or it will generate a rlock instance of itself.
It can be considered that, in addition to the lock pool with lock, condition also contains a wait pool in which the thread in the pool waits for a blocking state until another thread calls the Notify ()/notifyall () notification, and the thread enters the lock pool waiting to be locked after being notified.
Construction Method:
Condition ([Lock/rlock])
Instance method:
Acquire ([timeout])/release (): the appropriate method to invoke the associated lock.
Wait ([timeout]): Calling this method will cause the thread to enter the condition waiting pool for notification and release the lock. The use of a thread must have been locked or an exception will be thrown.
Notify (): Calling this method will pick a thread from the waiting pool and notify that the thread receiving the notification will automatically call acquire () to try to get the lock (into the lock pool); Other threads are still waiting in the pool. Calling this method does not release the lock. The use of a thread must have been locked or an exception will be thrown.
Notifyall (): Calling this method will notify all threads in the waiting pool that these threads will enter the lock pool to try to acquire a lock. Calling this method does not release the lock. The use of a thread must have been locked or an exception will be thrown.
Examples are the most common producer/consumer models:
The code is as follows:
# Encoding:utf-8
Import threading
Import time
# Merchandise
Product = None
# condition Variable
Con = threading. Condition ()
# producer Methods
def produce ():
Global product
If Con.acquire ():
While True:
If product is None:
print ' Produce ... '
Product = ' anything '
# Inform consumers that the goods have been produced
Con.notify ()
# Waiting to be notified
Con.wait ()
Time.sleep (2)
# Consumer Methods
def consume ():
Global product
If Con.acquire ():
While True:
If product is not None:
print ' Consume ... '
Product = None
# inform the producer that the goods are gone
Con.notify ()
# Waiting to be notified
Con.wait ()
Time.sleep (2)
T1 = Threading. Thread (Target=produce)
T2 = Threading. Thread (Target=consume)
T2.start ()
T1.start ()
3.5. Semaphore/boundedsemaphore
Semaphore (semaphore) is one of the oldest synchronization instructions in the history of computer science. Semaphore manages a built-in counter that, whenever acquire () is invoked-1, calls release () at +1. The counter cannot be less than 0, and when the counter is 0 o'clock, acquire () blocks the thread to the synchronized lock state until the other thread invokes release ().
Based on this feature, semaphore is often used to synchronize some objects with a "visitor cap", such as a connection pool.
The only difference between Boundedsemaphore and semaphore is that the former will check that the value of the counter exceeds the counter's initial value when the release () is invoked, and an exception is thrown if it is exceeded.
Construction Method:
Semaphore (value=1): value is the initial value of the counter.
Instance method:
Acquire ([timeout]): request semaphore. If the counter is 0, the thread is blocked to the synchronized blocking state, otherwise the counter-1 is returned immediately.
Release (): Releases the semaphore, counters +1, and if Boundedsemaphore is used, the number of releases is checked. The release () method does not check whether the thread has obtained semaphore.
The code is as follows:
# Encoding:utf-8
Import threading
Import time
# Counter initial value is 2
Semaphore = Threading. Semaphore (2)
def func ():
# request semaphore, after success counter-1; counter is blocked 0 o'clock
print '%s acquire semaphore ... '% threading.currentthread (). GetName ()
If Semaphore.acquire ():
print '%s get semaphore '% threading.currentthread (). GetName ()
Time.sleep (4)
# release semaphore, counter +1
Print '%s release semaphore '% Threading.currentthread (). GetName ()
Semaphore.release ()
T1 = Threading. Thread (Target=func)
T2 = Threading. Thread (Target=func)
T3 = Threading. Thread (Target=func)
T4 = Threading. Thread (Target=func)
T1.start ()
T2.start ()
T3.start ()
T4.start ()
Time.sleep (2)
# The main thread that does not get Semaphore can also call release
# throws an exception if you use BOUNDEDSEMAPHORE,T4 to release semaphore
print ' Mainthread release semaphore without acquire '
Semaphore.release ()
3.6. Event
Event is one of the simplest threading mechanisms: one thread notifies an event, and another thread waits for the event. The event has a built-in flag that is initially false, set to True when the set () is invoked, and reset to False when the clear () is invoked. Wait () will block the thread until it waits for a blocking state.
Event is actually a simplified version of the Condition. The event has no lock and cannot cause the thread to enter a synchronized blocking state.
Construction Method:
Event ()
Instance method:
IsSet (): Returns True when the built-in flag is true.
Set (): Sets the flag to true and notifies all threads waiting to be blocked to resume running.
Clear (): Sets the flag to false.
Wait ([timeout]): If the flag returns immediately if it is true, it will block the thread until it waits for the blocking state, waiting for the other thread to call set ().
The code is as follows:
# Encoding:utf-8
Import threading
Import time
event = Threading. Event ()
def func ():
# Wait for the event, enter the wait-blocking state
print '%s ' Wait for event ... '% threading.currentthread (). GetName ()
Event.wait ()
# Enter the running state after receiving the event
print '%s recv event. '% Threading.currentthread (). GetName ()
T1 = Threading. Thread (Target=func)
T2 = Threading. Thread (Target=func)
T1.start ()
T2.start ()
Time.sleep (2)
# Send Event notification
print ' Mainthread set event. '
Event.set ()
3.7. Timer
A timer (timer) is a derived class of thread that is used to invoke a method after a specified time.
Construction Method:
Timer (interval, function, args=[], kwargs={})
Interval: Specified time
Function: Method to execute
Args/kwargs: Parameter of method
Instance method:
The timer derives from thread without adding an instance method.
The code is as follows:
# Encoding:utf-8
Import threading
def func ():
print ' Hello timer! '
Timer = Threading. Timer (5, func)
Timer.start ()
3.8. Local
A local is a class that starts with a lowercase letter and is used to manage thread-local (thread-partial) data. For the same local, the thread cannot access the properties set by the other thread; The properties set by the thread are not replaced by the same name as the other thread set.
You can think of local as a "threading-Attribute Dictionary" dictionary, where local encapsulates the details of retrieving the corresponding property dictionary from its own thread as a key, and then using the property name as the key to retrieve the property value.
The code is as follows:
# Encoding:utf-8
Import threading
Local = Threading.local ()
Local.tname = ' main '
def func ():
Local.tname = ' Notmain '
Print Local.tname
T1 = Threading. Thread (Target=func)
T1.start ()
T1.join ()
Print Local.tname
Mastering thread, Lock, and condition can deal with most situations where threads are needed, and in some cases local is also very useful. This article concludes by using these classes to show the scenarios mentioned in the thread base:
Copy code code as follows:
# Encoding:utf-8
Import threading
Alist = None
Condition = Threading. Condition ()
Def doset ():
If Condition.acquire ():
While Alist is None:
Condition.wait ()
For I in range (len (alist)) [::-1]:
Alist[i] = 1
Condition.release ()
Def doprint ():
If Condition.acquire ():
While Alist is None:
Condition.wait ()
For I in Alist:
Print I,
Print
Condition.release ()
Def docreate ():
Global Alist
If Condition.acquire ():
If Alist is None:
Alist = [0 for I in range (10)]
Condition.notifyall ()
Condition.release ()
Tset = Threading. Thread (target=doset,name= ' Tset ')
Tprint = Threading. Thread (target=doprint,name= ' Tprint ')
Tcreate = Threading. Thread (target=docreate,name= ' tcreate ')
Tset.start ()
Tprint.start ()
Tcreate.start ()
Complete Full text