GIL The full name is Global Interpreter Lock( Global interpreter lock ), For data security ,GIL Ensure that only one thread can get data at the same time . therefore , stay python in , Only one thread can be executed at the same time .
and IO intensive , Multithreading can effectively improve efficiency ( Under single thread IO The operation will go on IO wait for , Cause unnecessary waste of time , And multithreading can be enabled in threads A When waiting for , Automatically switch to thread B, Can not waste CPU Resources for , It can improve the efficiency of program execution ). therefore python Multithreaded pair IO Dense code is more friendly .
and CPU intensive ( All kinds of recycling 、 Calculation and so on ), Because of the calculation work , The timer will soon reach the threshold , then Trigger GIL The release and re competition of ( Switching multiple threads back and forth is of course resource consuming ), therefore python Multithreaded pair CPU Dense code is not friendly .
Python When using multithreading , It's called c The native thread of language .
note : Some don't understand ?
threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
When calling this constructor , Must have a keyword parameter . The parameters are as follows :
group Should be None; For future expansion ThreadGroup Class implementation while retaining .
target Is used for run() Method called Callable object ( A function ). The default is None, Indicates that no method needs to be called .
name yes Thread name . By default , from “Thread-N” The format forms a unique name , among N It's a small decimal number . Multiple threads can be given the same name .
args Is used to call the object function Parameter tuple . The default is ().
kwargs Is used to call the object function Keyword parameter Dictionary . The default is {}.
daemon If the parameter is not None, Whether the thread is in daemon mode will be explicitly set . If it is None ( The default value is ), Thread will Inherit Of the current thread Daemon mode properties .
3.3 Version and above only have this attribute .
Be careful : Be sure to call start() Set before , Otherwise it will throw RuntimeError .
The initial value is inherited from the creation thread ; The main thread is not a daemon thread , Therefore, all threads created by the main thread are... By default daemon = False.
When there are no surviving non daemon threads , Whole Python The program will exit .
If subtype ** Overloaded constructor ,** It must ensure that Before doing anything , First initiate Call base class constructor (Thread.init()).
A term is used to explain : Guardian mode
There is a thread , It's in Background operation Of , Its task is to serve other threads , This kind of thread is called “ Background thread (Daemon Thread)”, Also known as “ The guardian thread ” or “ Sprite threads ”.Python The garbage collection thread of the interpreter is a typical background thread .
Background threads have a feature , If all foreground threads die , Then the background thread will die automatically .
Start thread activity .
It's in One thread Most Can only be called once . It arranges the distribution of objects run() Method is invoked in an independent control process. .
If this method is called in the same thread object More than once , Meeting Throw out RuntimeError .
wait for , Until the end of the thread .
at present Blocking The thread that calls this method , Until it's called join() Thread termination for .
When timeout Parameters Exists and is not None when , It should be a to specify the timeout of the operation second Unit Floating point numbers ( Or scores ).
because join() Always returns None , So you have to be there join() after call is_alive() To determine whether a timeout has occurred , If the thread is still alive , be join() Overtime .
When timeout Parameter does not exist or None , This operation will Block until the thread ends .
One thread Can be join() Many times .
import threading # Thread module
import time
def run(n):
print("task", n)
time.sleep(1)
print('2s')
time.sleep(1)
print('3s')
if __name__ == '__main__':
th = threading.Thread(target=run,name="thread_1" args=("thread 1",), daemon=True) # Create thread
# Set the subprocess as the daemons ,** Must be in start() Set before
th.setDaemon(True) # Setting up the guardian thread , In fact, it has been Set up daemon=True
th.start()
# Set the main thread to wait for the child thread to end
th.join()
print("end")
Because there is random scheduling between threads , And each thread may only execute n After execution , When multiple threads modify the same data at the same time, it may appear Dirty data ( note :Python Basic data type 、 list 、 Tuples 、 Dictionaries are thread safe , So it will not cause program crash , But it will lead to unknown values in the data , Dirty data ),
So there's a thread lock , That is, a thread is allowed to perform operations at the same time . Thread locks are used to lock resources , Multiple locks can be defined , Like the code below , When you need to monopolize a resource , Any lock can lock this resource , It's like you can lock the same door with different locks .
Because threads are randomly scheduled , If multiple threads operate on an object at the same time , And the object is not well protected , An unexpected result of the program , So we call it “ Thread unsafe ”.
To prevent this from happening , There's a lock .
I am here 5 Kind of Python Thread lock Detailed in .
Concept supplement :
Following points 5 There are different forms of explanation join Use in multithreaded programming
Python Multithreading is the default ( Set thread setDaemon(False)), After the main thread finishes its task , Dropped out , At this point, the sub thread will continue to perform its own tasks , Until the end of my mission
note :setDaemon(False) namely This thread is set as a non daemon thread ; After the main program exits , The child thread does not exit automatically .
import threading, time
def doWaiting1():
print('start waiting1: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(3)
print(" Threads 1 Have been ordered to report ")
print('stop waiting1: ' + time.strftime('%H:%M:%S') + "\n")
def doWaiting2():
print('start waiting2: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(8)
print(" Threads 2 Have been ordered to report ")
print('stop waiting2: ', time.strftime('%H:%M:%S') + "\n")
tsk = [] # The thread list
# Create and start threads 1
thread1 = threading.Thread(target = doWaiting1)
thread1.start() # start() function The actual call RUN() function (Python It's called C Thread of language )
tsk.append(thread1)
# Create and start threads 2
thread2 = threading.Thread(target = doWaiting2)
thread2.start()
tsk.append(thread2)
# Timing program
print('start join: ' + time.strftime('%H:%M:%S') )
print('end join: ' + time.strftime('%H:%M:%S') )
Running results
start waiting1: 20:03:30
start waiting2: 20:03:30
start join: 20:03:30
end join: 20:03:30 # Here the main thread has ended , And the child thread is still working
Threads 1 Have been ordered to report # Sub thread 1 Keep working
stop waiting1: 20:03:33
Threads 2 Have been ordered to report
stop waiting2: 20:03:38
Conclusion :
Open thread **setDaemon(True),** Set the child thread as the guardian thread , Realize the end of the main program , The subroutine immediately ends all functions
import threading, time
def doWaiting1():
print('start waiting1: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(3)
print(" Threads 1 Have been ordered to report ")
print('stop waiting1: ' + time.strftime('%H:%M:%S') + "\n")
def doWaiting2():
print('start waiting2: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(8)
print(" Threads 2 Have been ordered to report ")
print('stop waiting2: ', time.strftime('%H:%M:%S') + "\n")
tsk = []
# Create and start threads 1
thread1 = threading.Thread(target = doWaiting1)
thread1.setDaemon(True)
thread1.start()
tsk.append(thread1)
# Create and start threads 2
thread2 = threading.Thread(target = doWaiting2)
thread2.setDaemon(True)
thread2.start()
tsk.append(thread2)
print('start join: ' + time.strftime('%H:%M:%S') )
print('end join: ' + time.strftime('%H:%M:%S') )
Running results :
start waiting1: 20:10:04
start waiting2: 20:10:04
start join: 20:10:04
end join: 20:10:04 # After the main thread ends , The child thread ends immediately , In whatever state .
Conclusion :
Non-daemon thread , The main program will wait until all subroutines are completed
import threading, time
def doWaiting1():
print('start waiting1: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(3)
print(" Threads 1 Have been ordered to report ")
print('stop waiting1: ' + time.strftime('%H:%M:%S') + "\n")
def doWaiting2():
print('start waiting2: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(8)
print(" Threads 2 Have been ordered to report ")
print('stop waiting2: ', time.strftime('%H:%M:%S') + "\n")
tsk = []
# Create and start threads 1
thread1 = threading.Thread(target = doWaiting1)
thread1.start()
tsk.append(thread1)
# Create and start threads 2
thread2 = threading.Thread(target = doWaiting2)
thread2.start()
tsk.append(thread2)
print('start join: ' + time.strftime('%H:%M:%S') )
for t in tsk:
print('%s The thread is here '%t)
t.join() # Threads join() namely : Two threads run again , You cannot proceed to the next line until all are completed
print('end join: ' + time.strftime('%H:%M:%S') )
Running results :
start waiting1: 20:14:35
start waiting2: 20:14:35
start join: 20:14:35
<Thread(Thread-1, started 19648)> The thread is here
Threads 1 Have been ordered to report
stop waiting1: 20:14:38
<Thread(Thread-2, started 24056)> The thread is here
Threads 2 Have been ordered to report
stop waiting2: 20:14:43
end join: 20:14:43 # After the two threads are executed , To run to this
Conclusion :
to join Set up timeout The number , It is judged that the child thread has not completed after waiting for more than one time , The main thread no longer waits
note :join Set after timeout , The judgment is based on Sub thread execution completed | Overtime ( Logical or relationship ), Which of the two conditions is true first , Just go down .
import threading, time
def doWaiting1():
print('start waiting1: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(2)
print(" Threads 1 Have been ordered to report ")
print('stop waiting1: ' + time.strftime('%H:%M:%S') + "\n")
def doWaiting2():
print('start waiting2: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(8)
print(" Threads 2 Have been ordered to report ")
print('stop waiting2: ', time.strftime('%H:%M:%S') + "\n")
tsk = []
# Create and start threads 1
thread1 = threading.Thread(target = doWaiting1)
thread1.start()
tsk.append(thread1)
# Create and start threads 2
thread2 = threading.Thread(target = doWaiting2)
thread2.start()
tsk.append(thread2)
print('start join: ' + time.strftime('%H:%M:%S') )
for t in tsk:
print(" Start :"+time.strftime('%H:%M:%S'))
print('%s The thread is here '%t)
t.join(5)
print(" end :" + time.strftime('%H:%M:%S'))
print('end join: ' + time.strftime('%H:%M:%S') )
Running results :
start waiting1: 21:14:25
start waiting2: 21:14:25
start join: 21:14:25
Start :21:14:25
<Thread(Thread-1, started 22348)> The thread is here
Threads 1 Have been ordered to report
stop waiting1: 21:14:27
end :21:14:27
Start :21:14:27
<Thread(Thread-2, started 13164)> The thread is here
end :21:14:32
end join: 21:14:32
Threads 2 Have been ordered to report
stop waiting2: 21:14:33
Conclusion :
Child threads that have timed out and have not finished processing will be terminated directly ( Conform to the characteristics of daemon thread )
import threading, time
def doWaiting1():
print('start waiting1: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(2)
print(" Threads 1 Have been ordered to report ")
print('stop waiting1: ' + time.strftime('%H:%M:%S') + "\n")
def doWaiting2():
print('start waiting2: ' + time.strftime('%H:%M:%S') + "\n")
time.sleep(8)
print(" Threads 2 Have been ordered to report ")
print('stop waiting2: ', time.strftime('%H:%M:%S') + "\n")
tsk = []
# Create and start threads 1
thread1 = threading.Thread(target = doWaiting1)
thread1.setDaemon(True) # The guardian thread
thread1.start()
tsk.append(thread1)
# Create and start threads 2
thread2 = threading.Thread(target = doWaiting2)
thread2.setDaemon(True) # The guardian thread
thread2.start()
tsk.append(thread2)
print('start join: ' + time.strftime('%H:%M:%S') )
for t in tsk:
print(" Start :"+time.strftime('%H:%M:%S'))
print('%s The thread is here '%t)
t.join(5)
print(" end :" + time.strftime('%H:%M:%S'))
print('end join: ' + time.strftime('%H:%M:%S') )
Running results :
start waiting1: 21:24:14
start waiting2: 21:24:14
start join: 21:24:14
Start :21:24:14
<Thread(Thread-1, started daemon 9060)> The thread is here
Threads 1 Have been ordered to report
stop waiting1: 21:24:16
end :21:24:16
Start :21:24:16
<Thread(Thread-2, started daemon 13912)> The thread is here
end :21:24:21
end join: 21:24:21
Conclusion :
Catalog ( You can click on the