This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!

The purpose of multithreading in a project

Specific principle I think this should be able to jump into the operating system inside a little bit of a small summary you can also find the operating system book to see, the old rules can not find the words to find my home page, there is an article about resources there are resources, of course, you can also private message me. Let’s talk about the purpose of using multithreading in our project: 1. It is very easy to share memory between threads. 2. Using multithreading for concurrent execution of multiple tasks is more efficient than using multiple processes. 3. Sometimes it saves running time, as we’ll see later

Multithreaded programming in Python is simplified by the built-in support for multithreading in the python language, rather than simply being used as a scheduler for the underlying operating system.Copy the code

Practical operation

Said so much worse than the actual hands-on practice, first import thread Special note: we don’t see the build file name and the imported packages as threading or will go wrong.

The little knowledge

import threading
Copy the code

Let’s first look at how many processes our program has

import threading
def main() :
    print(threading.current_thread())

if __name__ == '__main__':
    main()
Copy the code
Results:1# MyOnly One Where's yours?
Copy the code

You can also do this if you don’t have one process

import threading
def main() :
    print(threading.active_count())
    print(threading.enumerate())
   

if __name__ == '__main__':
    main()
Copy the code
>>>[<_MainThread(MainThread, started 36004) >]# returns a list because I only have one so there is only one main process
Copy the code

You can also view the processes that are running

import threading
def main() :
    print(threading.active_count())
    print(threading.enumerate())
    print(threading.current_thread())

if __name__ == '__main__':
    main()
Copy the code
>1
[<_MainThread(MainThread, started 36004)>]
<_MainThread(MainThread, started 36004) >Copy the code

Create a simple thread

Let’s start with an introductionThreading. Thread ()It is better to look at the source file to learn the functions of each module in Python. This will help you improve your programming skills:

I’ve marked the points that need attention

import threading
def first() :
    print("frist active")
    print("frist finish")

def main() :
    first_thread=threading.Thread(target=first,name="T1")
    first_thread.start()The # start sign
    print("main")

if __name__ == '__main__':
    main()
Copy the code
Result: Run frist Active Main frist Finish the first time and frist active Frist Finish main the second timeCopy the code

The fact that the results are different each time indicates that Frist and main are running simultaneously. If it doesn’t work that well, let’s improve it and let’s introduce

import time
Copy the code
import threading
import time
def first() :
    print("frist active")
    time.sleep(3)
    print("frist finish")

def main() :
    first_thread=threading.Thread(target=first,name="T1")
    first_thread.start()
    print("main")

if __name__ == '__main__':
    main()
Copy the code
Result: Frist active main Frist finishCopy the code

Because by the time it gets to Frist active the Frist thread is asleep for 3 seconds while main is executing so it’s going to get this result every time.A special emphasis ontarget=firstInstead of importing the Frist function, we already know from the source file that this is done through the run () method, and I’m quoting a big name here

link

If you don’t want to do that, you can rewrite the run method in threading.Thresd to create a custom thread

    class MyThread(threading.Thread) :
        def __init__(self,n) :
            super(MyThread,self).__init__()   The run function must be written
            self.n = n

        def run(self) :
            print('task',self.n)
            time.sleep(1)
            print('2s')
            time.sleep(1)
            print('1s')
            time.sleep(1)
            print('0s')
            time.sleep(1)

    if __name__ == '__main__':
        t1 = MyThread('t1')
        t2 = MyThread('t2')
        t1.start()
        t2.start()
Copy the code
Result: Task T1 task T2 2s 2s 1s 1s 0sCopy the code

Daemon thread

The so-called thread daemon means that the main thread will be closed whenever other subthreads finish and the main thread finishes, regardless of the execution of the thread. That is: the main thread does not wait for the daemon thread to finish executing before closing.Copy the code

If it’s hard to understand, let’s look at an example

import threading
import time
def first() :
    print("frist active")
    time.sleep(3)
    print("frist finish")

def second() :
    print("second active")
    print("second finish")

def main() :
    first_thread=threading.Thread(target=first,name="T1")
    second_thresd=threading.Thread(target=second,name="T2")
    first_thread.setDaemon(True)# Always start before start ()
    first_thread.start()
    second_thresd.start()
    print("main")

if __name__ == '__main__':
    main()
    

Copy the code
Result Frist active second Active second FinishJiemeijieshu mainCopy the code

When both the main thread and the other subthreads terminate, the program terminates regardless of whether the daemon thread “first_thread” terminates. This is the case when you set second_thresd as the daemon thread

import threading
import time
def first() :
    print("frist active")
    time.sleep(3)
    print("frist finish")

def second() :
    print("second active")
    print("second finish")

def main() :
    first_thread=threading.Thread(target=first,name="T1")
    second_thresd=threading.Thread(target=second,name="T2")
    second_thresd.setDaemon(True)# Always start before start ()
    first_thread.start()
    second_thresd.start()
    print("main")

if __name__ == '__main__':
    main()
    


Copy the code
frist active
second active
second finish
main
frist finish # Although it takes three seconds to output this
Copy the code

The main process waits for the child process to finish

In order for the main thread to finish after the daemon thread finishes executing, we can use the join method to make the main thread wait for the child thread to execute

import threading
import time
def first() :
    print("frist active")
    time.sleep(3)
    print("frist finish")

def second() :
    print("second active")
    print("second finish")

def main() :
    first_thread=threading.Thread(target=first,name="T1")
    second_thresd=threading.Thread(target=second,name="T2")
    first_thread.start()
    second_thresd.start()
    first_thread.join()

    print("main")

if __name__ == '__main__':
    main()
    


Copy the code
Results: Frist Active Second Active Second Finish Frist Finish main Frist Active Second Active second Finish main frist finishCopy the code

Shared features of global variables

Here we define A global variable A

import threading
import time
def first() :
    global A
    print("frist active")
    time.sleep(3)
    A=A+3
    print("frist:%d"%A)
    print("frist finish")

def second() :
    global A
    print("second active")
    A=A+6
    print("second:%d"%A)
    print("second finish")

def main() :
    global A
    first_thread=threading.Thread(target=first,name="T1")
    second_thresd=threading.Thread(target=second,name="T2")
    first_thread.start()
    second_thresd.start()
    #first_thread.join()

    print("main")
    A=A+3
    print("mian:%d"%A)

if __name__ == '__main__':
    A=0
    main()




Copy the code

Let’s look at the results

frist active
second active
second:6
second finish
main
mian:9
frist:12
frist finish
Copy the code

The lock

As you can see from the example above, when the value of A is printed, the resources between different processes are shared. This leads to the situation where the value of variable A is not fixed and dirty data is generated.

In the absence of a mutex, assuming the account has $10,000, you can deposit and withdraw money at the same time with a balance of $11,000. I’d be happy to but the bank wouldn’t let me. To avoid this, let’s introduce the concept of locking. Let’s briefly introduce a few common ones in programming.

The mutex

import threading
import time
def first() :
    global A,lock
    lock.acquire()
    print("frist active")
    time.sleep(3)
    A=A+3
    print("frist:%d"%A)
    print("frist finish")
    lock.release()

def second() :
    global A,lock
    lock.acquire()
    print("second active")
    A=A+6
    print("second:%d"%A)
    print("second finish")
    lock.release

def main() :
    global A,lock
    lock=threading.Lock()
    first_thread=threading.Thread(target=first,name="T1")
    second_thresd=threading.Thread(target=second,name="T2")
    first_thread.start()
    second_thresd.start()
    #first_thread.join()

    print("main")
    A=A+3
    print("mian:%d"%A)

if __name__ == '__main__':
    A=0
    main()

Copy the code

The results of

frist active
main
mian:3
frist:6
frist finish
second active
second:12
second finish

Copy the code

Isn’t that more comfortable? If it’s not obvious let’s do another one

import threading
import time
def first() :
    global A,lock
    lock.acquire()
    print("frist active")
    time.sleep(3)
    A=A+3
    print("frist1:%d"%A)
    A = A + 3
    print("frist2:%d" % A)
    print("frist finish")
    lock.release()

def second() :
    global A,lock
    lock.acquire()
    print("second active")
    A=A+6
    print("second1:%d"%A)
    A=A+6
    print("second2:%d"%A)

    print("second finish")
    lock.release()

def main() :
    global A,lock
    lock=threading.Lock()
    first_thread=threading.Thread(target=first,name="T1")
    second_thresd=threading.Thread(target=second,name="T2")
    first_thread.start()
    second_thresd.start()
    #first_thread.join()

    print("main")
    A=A+3
    print("mian:%d"%A)

if __name__ == '__main__':
    A=0
    main()

Copy the code

The results of

frist active
main
mian:3
frist1:6
frist2:9
frist finish
second active
second1:15
second2:21Second finish Frist active second active second1:6
second2:12
second finish
main
mian:15
frist1:18
frist2:21
frist finish

Copy the code

Obviously, the results are messy when you remove the lock

A semaphore

I believe that I have a certain understanding of the operating system, and I have semaphore in mind when I mentioned locking, after all, the exam questions often appear, synchronization, mutex and semaphore mechanism. We have to say a semaphore lock, in fact, the rule is simple if you now, to get married in China you can only marry a wife, even though you can go to find another woman but they cannot be called a wife they will be called a little three, mistress, and so on, the wife here in China, the semaphore is a = = = = can have only one, the other can’t again.

import threading
import time

def run(n,semaphore) :
    semaphore.acquire()   # lock
    time.sleep(3)
    print('run the thread:%s\n' % n)
    semaphore.release()    # release


if __name__== '__main__':
    num=0
    semaphore = threading.BoundedSemaphore(3)   # Allow up to 3 threads to run simultaneously
    for i in range(10):
        t = threading.Thread(target=run,args=('t-%s' % i,semaphore))
        t.start()
    whilethreading.active_count() ! =1:
        pass
    else:
        print('----------all threads done-----------')

Copy the code

The results of

run the thread:t-2
run the thread:t-1


run the thread:t-0

run the thread:t-3
run the thread:t-5
run the thread:t-4



run the thread:t-6

run the thread:t-7

run the thread:t-8

run the thread:t-9

----------all threads done-----------

Copy the code

Give some resources

If you want to continue to explore the thread and you don’t have the resources, I have a book on the operating system, you can send me a private message oh, well, that’s all for today’s study. Don’t forget to click “like”