This article example analyzes python multithreading usage. Shared for your reference. Specific as follows:
Today, while studying to try to learn python multithreading, I suddenly realized that I've never been very clear about the usage of super, so I'll start by summarizing some of the problems I encountered. When I tried to write the following code:
def __init__( self ):
print "A"
class B( A ):
def __init__( self ):
super( B, self ).__init__( )
# A.__init__( self )
print "B"
b = B()
Appearance:
super( B, self ).__init__()
TypeError: must be type, not classobj
In the end, it turned out to be a problem with new-style classes in python, i.e., A must be a new-style class. The two solutions are as follows:
(1)
def __init__( self ):
print "A"
class B( A ):
def __init__( self ):
super( B, self ).__init__( )
# A.__init__( self ) ## This statement is old-fashioned and potentially problematic and should be avoided
print "B"
b = B()
(2)
class A():
def __init__( self ):
print "A"
class B( A ):
def __init__( self ):
super( B, self ).__init__( )
# A.__init__( self ) ## This statement is old-fashioned and potentially problematic and should be avoided
print "B"
b = B()
take note of: If you add a new code to super( B, self ). __init__( )
Adding self to the statement, that is, super( B, self ). __init__( self ), the following error occurs:
super( B, self ).__init__( self )
TypeError: __init__() takes exactly 1 argument (2 given)
The above is just a little bit of my notes, huh?
class myThread( ):
def __init__( self, threadname = "" ):
#.__init__( self, name = threadname )
super( myThread, self ).__init__( name = threadname )
def run( self ):
print "starting====", , ()
( 5 )
print "end====", , (),
m = myThread( "m" )
n = myThread( "n" )
()
()
Output:
starting==== m Mon Aug 08 21:55:41 2011
starting==== n Mon Aug 08 21:55:41 2011
If the main thread of a process finishes running while the child threads are still executing, the process does not exit until all child threads have finished. For example, the following example:
class myThread( ):
def __init__( self, threadname = "" ):
#.__init__( self, name = threadname )
super( myThread, self ).__init__( name = threadname )
def run( self ):
print "starting====", , ()
( 5 )
print "end====", , (),
m = myThread( "m" )
()
print "main end"
The output is:
starting==== m Mon Aug 08 22:01:06 2011
main end
end==== m Mon Aug 08 22:01:11 2011
That is, the child process is not terminated after the master process is terminated
We should use the setDaemon() function if we want the child process to end when the main process ends.
Examples are as follows:
class myThread( ):
def __init__( self, threadname = "" ):
#.__init__( self, name = threadname )
super( myThread, self ).__init__( name = threadname )
def run( self ):
print "starting====", , ()
( 5 )
print "end====", , (),
m = myThread( "m" )
( True )
()
print "main end"
The output is: starting ====main end m Mon Aug 08 22:02:58 2011
As you can see, it doesn't print the "end===..." that should have been printed when the child process m ended.
Simple thread synchronization
If you only read shared data, it's fine, but if multiple threads are trying to modify shared data, it can lead to unforeseen results.
If two thread objects t1 and t2 both want to increment the value num=0 by 1, then t1 and t2 each modify num 10 times, then the final result of num should be 20. However, if when t1 obtains the value of num (if num is 0 at this time), the system schedules t1 to the "sleeping" state and t2 to the "running" state, then t2 obtains the value of num, which is also 0, and assigns num+1 value 1 to num. "state, and at this time t2 converted to "running" state, at this time t2 obtained the value of num is also 0, and then he assigned the value of num +1 1 to num. the system also converted t2 to "sleeping The system transforms t2 into a "sleeping" state, and t1 into a "running" state, because t1 has already obtained a num value of 0, so he also assigns the value of num+1 to num as 1. Originally, it was running with 2 increments of 1, but it turned out that num was only incremented 1 time. Such a situation in the simultaneous execution of multiple threads is likely to occur. So in order to prevent this kind of situation to use thread synchronization mechanism.
The simplest synchronization mechanism is the "lock".
Lock objects are created with classes
How can a lock be used to synchronize a thread? Threads can use the acquire() method of a lock, which puts the lock into a "locked" state. Only one thread can acquire the lock at a time. If another thread tries to acquire the lock, it will be "blocked" until the thread that owns the lock calls the lock's release() method, which puts the lock into the "unlocked "state. The thread in the "blocked" state receives a notification and has the right to acquire the lock. If more than one thread is "blocked", all of them will be unlocked first, and then the system will choose one thread to acquire the lock, while the other threads will remain silent ("blocked"). blocked").
mylock = ()
class mythread()
...
def run(self ...):
... #You can't put code that modifies shared data here.
()
... # Here you can place the code to modify the shared data
()
... #You can't put code that modifies shared data here.
We refer to code that modifies shared data as "critical zones", and all "critical zones" must be enclosed between require() and release() method calls on the same lock object.
Locks can only provide the most basic level of synchronization. Sometimes more complex thread synchronization is needed, such as accessing a critical zone only when certain events occur (e.g. when a value changes). This requires the use of "conditional variables".
Conditional variables are created with classes
How do conditionals work? First a thread acquires a conditional variable successfully, calling the wait() method of the conditional variable causes the thread to release the lock and enter a "blocked" state until another thread calls the notify() method of the same conditional variable to wake up the thread that entered the "blocked" state. until another thread calls the notify() method of the same condition variable to wake up the thread in the "blocked" state. If the notifyAll() method of this condition variable is called, it will wake up all the waiting threads.
Deadlocks occur when a program or thread is permanently "blocked". Therefore, if you use synchronization mechanisms such as locks and conditional variables, you must be careful to double-check them to prevent deadlocks from occurring. For critical areas that may generate exceptions, use the finally clause in the exception handling mechanism to ensure that the lock is released. Threads waiting for a condition variable must be explicitly awakened with the notify() method or be silenced forever. Ensure that every wait() method call has a corresponding notify() call, and of course call the notifyAll() method just in case.
synchronized queue
We often use a producer/consumer relationship where two threads process data in a shared buffer. For example, a producer thread accepts user data into a shared buffer and waits for a consumer thread to retrieve the data. However, if the buffer is too small and the asynchronous threads of the producer and consumer have different speeds, it is easy for one thread to wait for the other. In order to minimize the waiting time for threads that share resources and work at the same speed, we can use a "queue" to provide an additional buffer.
To create a "Queue" object, use the following code:
myqueue = (maxsize = 10)
class is a synchronized implementation of a queue. The length of the queue can be infinite or finite. The queue length can be set with the optional parameter maxsize in the Queue's constructor. If maxsize is less than 1, the queue length is infinite.
Places a value into a queue:
(10)
Call the put() method of the queue object to insert an item at the end of the queue. put() has two parameters, the first item is required, for the insertion of the value of the item; the second block is an optional parameter, the default is 1. If the queue is currently empty and the block is 1, the put() method will make the calling thread to pause until a data unit is empty. If block is 0, the put method will raise a Full exception.
Removes a value from the queue:
()
Calls the get() method of a queue object to remove and return an item from the head of the queue. The optional argument is block, which defaults to 1. If the queue is empty and block is 1, get() pauses the calling thread until an item becomes available. If block is 0, the queue raises an Empty exception.
Let's use an example to show how to use Queue:
from Queue import Queue
import threading
import random
import time
# Producer thread
class Producer( ):
def __init__( self, threadname, queue ):
.__init__( self, name = threadname )
= queue
def run( self ):
for i in range( 20 ):
print (), 'adding', i, 'to queue'
( i )
( ( 10 ) / 10.0 )
print (), 'Finished'
# Consumer thread
class Consumer( ):
def __init__( self, threadname, queue ):
.__init__( self, name = threadname )
= queue
def run( self ):
for i in range( 20 ):
print (), 'got a value:', ()
( ( 10 ) / 10.0 )
print (), 'Finished'
# Main thread
def main():
queue = Queue()
producer = Producer( 'Producer', queue )
consumer = Consumer( 'Consumer', queue )
print 'Starting threads ...'
()
()
()
()
print 'All threads have terminated.'
if __name__ == '__main__':
main()
The output of the program is:
Starting threads ...
Producer adding 0 to queue
Consumer got a value: 0
Producer Finished
Producer adding 1 to queue
Producer Finished
Producer adding 2 to queue
Consumer Finished
Consumer got a value: 1
Consumer Finished
Consumer got a value: 2
Consumer Finished
Consumer got a value: Producer Finished
Producer adding 3 to queue
3
Consumer Finished
Consumer got a value: Producer Finished
Producer adding 4 to queue
4
ConsumerProducer Finished
ConsumerFinished
got a value:Producer adding 5 to queue
5
Consumer Finished
Consumer got a value: Producer Finished
Producer adding 6 to queue
Producer Finished
Producer adding 7 to queue
6
Consumer Finished
Consumer got a value: 7
Producer Finished
Producer adding 8 to queue
Producer Finished
Producer adding 9 to queue
Consumer Finished
Consumer got a value: 8
ConsumerProducer FinishedFinished
ConsumerProducer got a value:adding 109
to queue
Producer Finished
Producer adding 11 to queue
Producer Finished
Producer adding 12 to queue
ConsumerProducer FinishedFinished
ConsumerProducer got a value:adding 1310
to queue
Producer Finished
Producer adding 14 to queue
Consumer Finished
Consumer got a value: 11
Producer Finished
Producer adding 15 to queue
Producer Finished
Producer adding 16 to queue
Producer Finished
Producer adding 17 to queue
Producer Finished
Producer adding 18 to queue
Consumer Finished
Consumer got a value: 12
Producer Finished
Producer adding 19 to queue
Producer Finished
Consumer Finished
Consumer got a value: 13
Consumer Finished
Consumer got a value: 14
Consumer Finished
Consumer got a value: 15
Consumer Finished
Consumer got a value: 16
Consumer Finished
Consumer got a value: 17
Consumer Finished
Consumer got a value: 18
Consumer Finished
Consumer got a value: 19
Consumer Finished
All threads have terminated.
I hope that what I have described in this article will help you in your Python programming.