1. What is a thread?
A process is the unit in which an operating system allocates a program to execute resources, and a thread is an entity of a process that is the unit of CPU dispatch and allocation. A process must have a main thread, and we can create multiple threads in a single process to achieve multi-tasking.
--------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------
2. A program to implement a multi-tasking approach
As shown in the implementation of multitasking, we can use several methods.
(1) In the main process to open multiple child processes, the main process and a number of child processes together to process the task.
For more than one process to achieve multitasking, refer to my blog post: https://www.cnblogs.com/chichung/p/9532962.html
(2) Multiple child threads are opened in the main process, and the main thread and multiple child threads work together on the task.
(3) Multiple threads are opened in the main process, and multiple processes work together.
For multiple tasks, you can refer to my blog post: https://www.cnblogs.com/chichung/p/9544566.html
Note: Because a thread-safety issue occurs with multiple threads working together on a task, it is common to use multi-process + multi-tasking in development to achieve multitasking.
--------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------
3. How multithreading is created
Import= Threading. Thread (target=[function name],args=([parameters to pass into functions])) P1.start () # start P1 thread
Let's simulate multithreading for multitasking.
If you are using NetEase cloud music while listening to songs while downloading. NetEase Cloud Music is a process. If NetEase cloud Music internal program is multi-threaded to achieve multitasking, netease cloud music Open two sub-threads. One is used to cache music for playback now. One to download the music that the user wants to download. This is how the code framework is:
ImportThreadingImport Timedeflisten_music (name): whileTrue:time.sleep (1) Print(Name,"playing music now")defdownload_music (name): whileTrue:time.sleep (2) Print(Name,"Downloading music")if __name__=='__main__': P1= Threading. Thread (target=listen_music,args= ("NetEase Cloud Music",)) P2= Threading. Thread (target=download_music,args= ("NetEase Cloud Music",)) P1.start () P2.start () Output: NetEase cloud music is playing music NetEase cloud music is being downloaded music NetEase cloud music is playing music NetEase cloud music is playing music NetEase cloud music is downloading music NetEase cloud music is playing music NetEase cloud music is playing music NetEase cloud music is being downloaded tone Le NetEase Cloud music is playing music NetEase cloud music is playing music NetEase cloud music is playing music ...
Observe the above output code to know:
1.CPU is the way to execute a child thread in a time-slice poll. Within the CPU, time slices are allocated reasonably. When the time slice to a program, a program if in hibernation, will automatically switch to the B program.
2. Strictly speaking, the CPU is performing only one task at a certain point in time, but because the CPU is running faster and faster, because it looks like multiple tasks are executed together.
There is another way to create a thread in addition to the method above. You can write a class that inherits Threaing. Thread class, and then override the Run method of the parent class.
ImportThreadingImport TimeclassMyThread (Threading. Thread):defRun (self): forIinchRange (5): Time.sleep (1) Print(self.name,i) T1=MyThread () T2=MyThread () T3=MyThread () T1.start () T2.start () T3.start () Output: Thread-10Thread-30Thread-20Thread-1 1Thread-2 1Thread-3 1Thread-1 2Thread-3 2Thread-2 2Thread-1 3Thread-2 3Thread-3 3Thread-1 4Thread-2 4Thread-3 4
Run-time unordered, indicating that multiple tasks have been enabled.
--------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------
4. When the thread is opened and when it ends
(1)子线程何时开启,何时运行 当调用thread.start()时 开启线程,再运行线程的代码(2)子线程何时结束 子线程把target指向的函数中的语句执行完毕后,或者线程中的run函数代码执行完毕后,立即结束当前子线程(3)查看当前线程数量 通过threading.enumerate()可枚举当前运行的所有线程(4)主线程何时结束 所有子线程执行完毕后,主线程才结束
Import Threading Import Time def run (): for in range (5): time.sleep (1) print= Threading. Thread (target=Run) t1.start ()print(" where will I appear ") Output: Where will I appear 01234
Why does the code for the main process (main thread) appear first? Because the CPU takes a time-slice poll, if it polls the child thread and finds that he is going to hibernate 1s, he will first run the main thread. Therefore, the CPU's time slice polling method can guarantee the optimal operation of the CPU.
So what if I want the main process to output that sentence to run at the end? What should we do? The join () method is required at this time.
--------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------
5. Thread's Join () method
import threading import time def run (): for i in Range (5 1
print
(i) T1 = Threading. Thread (Target=run) T1.start () t1.join () print ( " Where will I appear " ) output: 0 1234 Where will I appear
The join () method can block the main process (note that only the main process can be blocked, and other child processes cannot be blocked) until the T1 child thread finishes executing and then unblocking.
--------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------
6. Threads can share global variables
This is a little experiment to know, so here is no nonsense.
--------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------
7. Problems with multi-threaded shared global variables
We open two sub-threads, the global variable is 0, we each thread to him to add 1, each thread plus 1 million times, this time there will be a problem, to see the code:
1 ImportThreading2 Import Time3 4num =05 6 defWork1 (loop):7 GlobalNum8 forIinchrange (loop):9 #equivalent to num + = 1Tentemp =Num Onenum = temp + 1 A Print(num) - - the defWork2 (loop): - GlobalNum - forIinchrange (loop): - #equivalent to num + = 1 +temp =Num -num = temp + 1 + Print(num) A at - if __name__=='__main__': -T1 = Threading. Thread (target=work1,args= (1000000,)) -T2 = Threading. Thread (TARGET=WORK2, args= (1000000,)) - T1.start () - T2.start () in - whileLen (Threading.enumerate ())! = 1: toTime.sleep (1) + Print(num) - the Output: *1459526#The global variable is added to this number after the first child thread ends $1588806#The global variable is added to this number after the second child thread endsPanax Notoginseng1588806#after all two threads have ended, the global variable is added to this number altogether.
Is it strange that I am not adding 1 million times per thread? Supposedly, the final result is 2 million. What is the problem?
We know that the CPU is executing several threads in a time-slice polling way.
Let's say my CPU polls to WORK1 (), NUM is 100, and when I run to line 10th, the time is over! At this time, the assignment, but not self-added! That is temp=100,num=100.
Then, the time slice polls the WORK2 () to make the assignment self-Add. It's num=101.
And back to the breakpoint at Work1 (), num=temp+1,temp=100, so num=101.
That's it! Num has less time to self-add!
After a number of times, such errors accumulate together, resulting in only 158806!
This is a thread safety issue !
--------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------
8.GIL Locks (mutexes) can compensate for some thread-safety issues. attention is part! As for the malpractice of the Gil Lock, please take care of my blog post.
Synchronous control is required when multiple threads modify a shared data at almost the same time
Thread synchronization ensures that multiple threads secure access to competing resources, and the simplest synchronization mechanism is to introduce mutexes.
Mutex introduces a state to a resource: locked/non-locked
When a thread changes the shared data, it locks it, the state of the resource is locked, the other thread cannot be changed, and until the thread frees the resource, the state of the resource becomes "non-locked", and the other thread can lock the resource again. The mutex ensures that only one thread is written at a time, thus guaranteeing the correctness of the data in multi-threaded situations.
Gil Locks have three common steps
Lock = Threading. Lock () # get lock lock.acquire () # lockout lock.release () # unlock
Let's use the Gil lock to solve the thread safety problem of the above example.
ImportThreadingImportTimenum=0lock= Threading. Lock ()#Get lockdefWork1 (loop):GlobalNum forIinchrange (loop):#equivalent to num + = 1Lock.acquire ()#lockedtemp =Num Num= temp + 1lock.release ()#Unlock Print(num)defWork2 (loop):GlobalNum forIinchrange (loop):#equivalent to num + = 1Lock.acquire ()#lockedtemp =Num Num= temp + 1lock.release ()#Unlock Print(num)if __name__=='__main__': T1= Threading. Thread (target=work1,args= (1000000,)) T2= Threading. Thread (TARGET=WORK2, args= (1000000,)) T1.start () T2.start ( ) whileLen (Threading.enumerate ())! = 1: Time.sleep (1) Print(num) output:1945267# Global variables add up to this number when the first child thread ends 2000000# Global variables add up to this number when the second child thread ends 2000000# After two threads are finished, the global variable is added to this number
Python Multithreading for multitasking