An in-depth explanation of multitasking processes, threads, and coroutines (python version)

Article directory

  • 1. Think about it?
  • 2. Main thread, sub-thread
  • 3. There is no order in which the main thread and sub-threads run – the necessity of delay
    • 3.1. Before delay
    • 3.2. After delay
  • 4. Encapsulate the thread and then call it (this method is not recommended)
  • 5. Multiple threads share global variables
    • 5.1 Process transfer participates in global list variable sharing (global is not required)
    • 5.2 Problems caused by global variable sharing

1. Think about it?

In theory, a single core can only complete one thing, but why can QQ, WeChat, Weibo, and Momo run on the same CPU? Because the running time of each software is very short, such as 0.0001s, this process is called: Time slice rotation algorithm (operating system algorithm). There is another way: Priority scheduling algorithm, which allows urgent tasks to be executed faster. This is actually false parallelism.

Parallelism: Really multi-tasking, so that the number of tasks is less than the number of CPU cores to maintain parallelism.
Concurrency: Fake multitasking. Currently, our computer tasks are many, and they are basically concurrent.

2. Main thread, sub-thread

import threading
import time

def saySorry():
    print("Dear, I was wrong, can I eat?")
    time.sleep(1)

if __name__ == "__main__": # The following code is the order in which the main thread runs
    for i in range(5):
        t = threading.Thread(target=saySorry)
        t.start() # Start the child thread

Main thread If there is no code, you must wait for child thread to end first. When the main thread ends, the entire program ends.

3. There is no order in which the main thread and sub-threads run – the necessity of delay

3.1, before delay

import threading


def test1():
    for i in range(5):
        print("----test1--%d---" % i)


def test2():
    for i in range(5):
        print("----test2--%d---" % i)


def main():
    t1 = threading.Thread(target=test1)
    t2 = threading.Thread(target=test2)

    t1.start()
    t2.start()

    print(threading.enumerate())


if __name__ == "__main__":
    main()
</code><img class="look-more-preCode contentImg-no-view" src="//i2.wp.com/csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreBlack.png" alt ="" title="">

Output:

D:\python_set\py3.9\python.exe D:/python_set/socket/3.py
----test1--0---
----test1--1---
----test1--2---
----test1--3---
----test1--4---
----test2--0---[<_MainThread(MainThread, started 15096)>, <Thread(Thread-2, started 13452)>]
----test2--1---

----test2--2---
----test2--3---
----test2--4---

Process finished with exit code 0

3.2, after delay

import threading
import time


def test1():
    for i in range(5):
        print("----test1--%d---" % i)


def test2():
    for i in range(5):
        print("----test2--%d---" % i)


def main():
    t1 = threading.Thread(target=test1)
    t2 = threading.Thread(target=test2)
# The child thread starts execution from star
    t1.start()
    # Main thread sleeps for 0.001s
    time.sleep(0.001)
    print("----1-----")
    t2.start()
    # Main thread sleeps for 0.001s
    time.sleep(0.001)
    print("----2-----")

    print(threading.enumerate())


if __name__ == "__main__":
    main()
</code><img class="look-more-preCode contentImg-no-view" src="//i2.wp.com/csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreBlack.png" alt ="" title="">

output

D:\python_set\py3.9\python.exe D:/python_set/socket/3.py
----test1--0---
----test1--1---
----test1--2---
----test1--3---
----test1--4---
----1-----
----test2--0---
----test2--1---
----test2--2---
----test2--3---
----test2--4---
----2-----
[<_MainThread(MainThread, started 13332)>]

4. Encapsulate the thread and then call it (this method is not recommended)

import threading
import time


class MyThread(threading.Thread):
    # The run method must be defined
    def run(self):
        self.name = 'hahah '
        for i in range(3):
            time.sleep(1)
            mes = "I'm" + self.name + "@" + str(i)
            print(mes)


if __name__ == "__main__":
    t = MyThread()
    t.start() # will call the run method directly
</code><img class="look-more-preCode contentImg-no-view" src="//i2.wp.com/csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreBlack.png" alt ="" title="">

5. Multiple threads share global variables

import threading
import time
#Define a global variable
g_num = 100


def test1():
    global g_num
    g_num + = 1
    print("-----in test1 g_num=%d----" % g_num)


def test2():
    print("----in test2 g_num=%d=-----" % g_num)


def main():
    t1 = threading.Thread(target=test1)
    t2 = threading.Thread(target=test2)

    t1.start()
    time.sleep(1)
    t2.start()
    time.sleep(1)

    print("-----in main Thread g_num = %d-----" % g_num)


if __name__ == "__main__":
    main()
</code><img class="look-more-preCode contentImg-no-view" src="//i2.wp.com/csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreBlack.png" alt ="" title="">

Output: The global variable value of all processes in the courseware is 101, which is shared.

-----in test1 g_num=101----
----in test2 g_num=101=-----
-----in main Thread g_num = 101-----

5.1 Process transfer participates in global list variable sharing (global is not required)

def test1(temp):
    temp.append(33)
    print("-----in test1 temp=%s----" % str(temp))


def test2(temp):
    print("----in test2 temp=%s=-----" % str(temp))


g_nums = [11, 22]


def main():
    # target specifies which function this thread goes to execute code
    #args specifies what parameters to pass in when calling the function in the future
    t1 = threading.Thread(target=test1, args=(g_nums,))
    t2 = threading.Thread(target=test2, args=(g_nums,))

    t1.start()
    time.sleep(1)
    t2.start()
    time.sleep(1)

    print("-----in main Thread g_nums = %s-----" % str(g_nums))


if __name__ == "__main__":
    main()
</code><img class="look-more-preCode contentImg-no-view" src="//i2.wp.com/csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreBlack.png" alt ="" title="">

5.2 Problems caused by global variable sharing

If g_num + = 1 is divided into three steps, when the second step is executed, the operating system says to get out of the CPU, and g_num is still stored. Then start thread 2 and run it for a few steps. The operating system says to get out of the CPU and thread 1 comes in. The operating system’s random interruption of the process leads to errors when global variables are shared.