Considerations for python threads

1. Introduction to thread precautions

Execution between threads is out of order
The main thread will wait for the execution of all child threads to end
Sharing global variables between threads
There was an error sharing global variable data between threads

2. The execution between threads is out of order

import threading
import time


def task():
    time.sleep(1)
    print("Current thread:", threading.current_thread().name)


if __name__ == '__main__':

   for _ in range(5):
       sub_thread = threading.Thread(target=task)
       sub_thread.start()
results of enforcement:

Current thread: Thread-1
 Current thread: Thread-2
 Current thread: Thread-4
 Current thread: Thread-5
 Current thread: Thread-3

explain:

The execution between threads is disordered, which is determined by cpu scheduling. Which thread is scheduled by cpu will execute first. Threads without scheduling cannot execute.
The execution between processes is also disordered. It is determined by the operating system scheduling. Which process the operating system schedules will be executed first. Processes without scheduling cannot be executed.

3. The main thread will wait for the execution of all sub threads to end

If we now create a sub thread, it will take about 2.5 seconds for the sub thread to execute. Now let the main thread execute for 1 second and exit the program. Check the execution results. The example code is as follows:

import threading
import time


#Test whether the main thread will wait for the execution of the child thread before exiting the program
def show_info():
    for i in range(5):
        print("test:", i)
        time.sleep(0.5)


if __name__ == '__main__':
    sub_thread = threading.Thread(target=show_info)
    sub_thread.start()

    # Main thread delay 1 second
    time.sleep(1)
    print("over")
results of enforcement:

test: 0
test: 1
over
test: 2
test: 3
test: 4

explain:

From the execution results of the above code, we can know that the main thread will wait for the execution of all sub threads to end

What if we let the main thread execute for one second and the sub thread is destroyed and no longer executed?

We can set the guard main thread
Guard main thread:

Guarding the main thread means that the main thread exits and the child thread is destroyed and no longer executed
There are two ways to set the guard main thread:

threading.Thread(target=show_info, daemon=True)
Thread object setDaemon(True)
Main code of daemon thread:

import threading
import time


#Test whether the main thread will wait for the execution of the child thread before exiting the program
def show_info():
    for i in range(5):
        print("test:", i)
        time.sleep(0.5)


if __name__ == '__main__':
    # Create a child thread to guard the main thread 
    # daemon=True guard the main thread
    # Guard main thread mode 1
    sub_thread = threading.Thread(target=show_info, daemon=True)
    # It is set as the guardian main thread. After the main thread exits, the sub thread directly destroys the code that no longer executes the sub thread
    # Guard main thread mode 2
    # sub_thread.setDaemon(True)
    sub_thread.start()

    # Main thread delay 1 second
    time.sleep(1)
    print("over")
results of enforcement:

test: 0
test: 1
over

3. Sharing global variables between threads

Requirements:

Define a global variable of list type
Create two sub threads to execute the task of adding data to the global variable and the task of reading data from the global variable respectively
Check whether global variable data is shared between threads

import threading
import time


#Define global variables
my_list = list()

#Write data task
def write_data():
    for i in range(5):
        my_list.append(i)
        time.sleep(0.1)
    print("write_data:", my_list)


# Read data task
def read_data():
    print("read_data:", my_list)


if __name__ == '__main__':
    # Create a thread to write data
    write_thread = threading.Thread(target=write_data)
    # Create a thread to read data
    read_thread = threading.Thread(target=read_data)

    write_thread.start()
    # delayed
    # time.sleep(1)
    # After the main thread waits for the write thread to finish executing, the code continues to execute
    write_thread.join()
    print("Start reading data")
    read_thread.start()
results of enforcement:

write_data: [0, 1, 2, 3, 4]
Start reading data
read_data: [0, 1, 2, 3, 4]

4. There is an error in sharing global variable data between threads

Requirements:

Define two functions to realize 1 million cycles, and add 1 to the global variable every cycle
Create two sub threads to execute the corresponding two functions and view the calculated results

import threading

#Define global variables
g_num = 0


#Loop once to add 1 to the global variable
def sum_num1():
    for i in range(1000000):
        global g_num
        g_num += 1

    print("sum1:", g_num)


#Loop once to add 1 to the global variable
def sum_num2():
    for i in range(1000000):
        global g_num
        g_num += 1
    print("sum2:", g_num)


if __name__ == '__main__':
    # Create two threads
    first_thread = threading.Thread(target=sum_num1)
    second_thread = threading.Thread(target=sum_num2)

    # Start thread
    first_thread.start()
    # Start thread
    second_thread.start()
results of enforcement:

sum1: 1210949
sum2: 1496035

Note:

Multithreading has an error in operating data on global variables at the same time

Error analysis:

Two threads first_thread and second_thread must be set to the global variable g_num(0 by default) adds 1. However, due to the simultaneous operation of multiple threads, the following situations may occur:

In G_ When num = 0, first_thread get g_num=0. At this point, the system sets the first_thread is scheduled to the "sleeping" state, and second_thread changes to the "running" state, and t2 also gets g_num=0
Then second_thread adds 1 to the obtained value and assigns it to g_num so that g_num=1
Then the system puts second_thread is scheduled as "sleeping", and the first_ Turn thread to "running". Thread t1 assigns its previous 0 plus 1 to g_num.
This leads to the first_thread and first_ Threads are all right for g_num plus 1, but the result is still g_num=1
Solution to global variable data error:

Thread synchronization: ensure that only one thread can operate global variable synchronization at the same time: cooperate with the pace and run in a predetermined order. If you finish, I'll say it again. It's like a walkie talkie in real life

Thread synchronization mode:

Thread wait (join)
mutex
Example code of thread waiting:

import threading

#Define global variables
g_num = 0


#Loop 1000000 times, adding 1 to the global variable each time
def sum_num1():
    for i in range(1000000):
        global g_num
        g_num += 1

    print("sum1:", g_num)


#Loop 1000000 times, adding 1 to the global variable each time
def sum_num2():
    for i in range(1000000):
        global g_num
        g_num += 1
    print("sum2:", g_num)


if __name__ == '__main__':
    # Create two threads
    first_thread = threading.Thread(target=sum_num1)
    second_thread = threading.Thread(target=sum_num2)

    # Start thread
    first_thread.start()
    # The main thread waits for the first thread to execute, and then the code continues to execute, allowing it to execute the second thread
    # Thread synchronization: after one task is completed, another task can be executed. At the same time, only one task is executing
    first_thread.join()
    # Start thread
    second_thread.start()
results of enforcement:

sum1: 1000000
sum2: 2000000

5. Summary

Thread execution is out of order
By default, the main thread will wait for the execution of all sub threads to end. The purpose of setting the guard main thread is to exit the main thread and destroy the sub threads.
The advantage of sharing global variables between threads is that the data of global variables can be shared.
Sharing global variables between threads may lead to data errors. Thread synchronization can be used to solve this problem.
Thread wait (join)

Keywords: Python Back-end

Added by eagleweb on Wed, 02 Feb 2022 11:35:05 +0200