This article is a learning note on Python core programming, introducing the global interpreter lock in Python and the usual two threading modules: Thread, threading, and comparing their pros and cons with a simple sample.
Global interpreter Lock (GIL)
The execution of Python code is controlled by Python virtual machines. When designing Python, consider that there can only be one control thread executing in the main loop, just like a single-core CPU for multithreaded programming.
How do you control that? This is the Gil here to control, this lock is used to ensure that only one thread is running at the same time.
Execution mode:
These few details point to the knowledge:
- When calling external code (a built-in function for C + + extensions), the Gil remains locked until the function execution is complete.
- For I/O-oriented python routines, the Gil is freed before I/O calls, allowing other threads to run during I/O execution
- If it is for computationally intensive operation code, the thread is more inclined to always occupy the processor and the Gil over the entire time slice.
So, for the design of the Python virtual machine single-threaded (GIL), only threads are performing I/O-intensive applications to better exploit Python's concurrency .
Compare thread,threading
Python multiple modules can be multithreaded programming, including: Thread,threading and so on. They can all be used to create and manage threads.
The thread module provides basic threading and locking support, while the threading module provides a higher level of more comprehensive thread management.
It is recommended to use a higher level threading module, here is a simple comparison:
Feature features |
Thread |
Threading |
Functional comprehensiveness |
Basic (on the bottom) |
Comprehensive, advanced |
Daemon process |
Not supported |
Support |
Thread Synchronization Primitives |
Only 1 (Lock) |
A lot (Lock,semaphore,barrier ...) |
Guardian Process Explained
A daemon is typically a server waiting for a client to request a service. If there is no client request, the daemon is generally idle. Generally, a thread is set as a daemon, which means that the thread is unimportant. so the process exits without waiting for the daemon to complete.
However, the original thread module does not distinguish between daemons or daemons, meaning that when the main thread exits, all child threads are terminated, regardless of whether they are still working. If you don't want this to happen, then you can use the threading module. The entire Python program (typically the main thread) exits when all non-daemons are exited.
Set the daemon before the thread starts:
thread.daemon = True
Multithreaded Practice Threading Instances
Mode 1: Create a thread instance, pass it a function
import threadingfrom time import sleep, ctimesleep_times = [4, 2]def loop(threadNo, sleep_time): print(‘Start loop‘, threadNo, ‘at:‘, ctime()) sleep(sleep_time) #Sleep一段时间 print(‘loop‘, threadNo, ‘done at:‘, ctime())def main(): print(‘starting at:‘, ctime()) threads = [] threadIds = range(len(sleep_times)) for i in threadIds: thread = threading.Thread(target=loop, args=(i,sleep_times[i])) threads.append(thread) for t in threads: # 依次启动线程 t.start() for t in threads: # 等待所有线程完成 t.join() #将等待线程结束 print(‘all Done at :‘, ctime())if __name__ == ‘__main__‘: main()
Method 2: Derive a subclass of thread and create an instance of the subclass
import threadingfrom time import sleep, ctimesleep_times = [4, 2]class MyThread(threading.Thread): def __init__(self, func, args, name=‘‘): threading.Thread.__init__(self) self.func = func self.name = name self.args = args def run(self): self.func(*self.args)def loop(threadNo, sleep_time): print(‘Start loop‘, threadNo, ‘at:‘, ctime()) sleep(sleep_time) # Sleep一段时间 print(‘loop‘, threadNo, ‘done at:‘, ctime())def main(): print(‘starting at:‘, ctime()) threads = [] # 用于存储所有线程实例的列表 threadIds = range(len(sleep_times)) for i in threadIds: # 创建线程实例 thread = MyThread(loop, (i, sleep_times[i])) threads.append(thread) for t in threads: # 依次启动线程 t.start() for t in threads: # 等待所有线程完成 t.join() # 将等待线程结束 print(‘all Done at :‘, ctime())if __name__ == ‘__main__‘: main()
Thread instance
Because I use the python3.6, this thread has become _thread
import _threadfrom time import sleep, ctimesleep_times = [4, 2]def loop(threadNo, sleep_time, lock): print(‘Start loop‘, threadNo, ‘at:‘, ctime()) sleep(sleep_time) #Sleep一段时间 print(‘loop‘, threadNo, ‘done at:‘, ctime()) lock.release() #释放锁def main(): print(‘starting at:‘, ctime()) locks = [] threadIds = range(len(sleep_times)) for i in threadIds: #通过调用_thread.allocate_lock获得锁对象 lock = _thread.allocate_lock() #通过acquire()方法取得锁 lock.acquire() locks.append(lock) for i in threadIds: # 依次启动线程 _thread.start_new_thread(loop, (i, sleep_times[i], locks[i])) for i in threadIds: # 如果当前的锁Lock没有释放的话,一直循环等待 while locks[i].locked(): pass print(‘all Done at :‘, ctime())if __name__ == ‘__main__‘: main()
Python 3 multi-threaded programming Learning notes-Basic article