SoFunction
Updated on 2024-11-15

Examples of python multithreading usage in detail

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:

Copy Code The code is as follows.
class A():
    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)

Copy Code The code is as follows.
class A( object ):
    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)

Copy Code The code is as follows.
__metaclass__=type
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?

Copy Code The code is as follows.
import threading, time
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:

Copy Code The code is as follows.
import threading, time
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"
print

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:

Copy Code The code is as follows.
import threading, time
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"
print

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

Copy Code The code is as follows.
mylock = ()

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

Copy Code The code is as follows.
import threading
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

Copy Code The code is as follows.
mycondition = ()

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:

Copy Code The code is as follows.
import Queue
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:

Copy Code The code is as follows.
# queue_example.py
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.