Python's Threading module creation thread

Source: Internet
Author: User
Tags mutex switches

A process is a system that allocates the smallest unit of resource allocation, a thread is an entity of a process, a basic unit of CPU dispatch and dispatch, and is a smaller unit that can run independently than a process. The process has independent memory units during execution, while multiple threads share resources such as memory.

Threading Module Creation Thread
import threadingfrom threading import Threaddef test(x):    print('this is {}'.format(x))    time.sleep(2)def get_thread(number=5):    l_thread = (Thread(target=test, args=(i,)) for i in range(number))    for t in l_thread:        print(t)        t.start() # 启动线程开始执行    print(len(threading.enumerate()))if __name__ == '__main__':    get_thread(5)# 结果<Thread(Thread-1, initial)>this is 0<Thread(Thread-2, initial)>this is 1<Thread(Thread-3, initial)>this is 2<Thread(Thread-4, initial)>this is 3<Thread(Thread-5, initial)>this is 46

From the above, we just need to create a thread object, and run the Start method, the interpreter will create a child process to execute our target, we created 5 threads, However, using Threading.enumerate to view the number of threads found there are 6 threads, because there is currently a main thread executing. The main thread waits for all child threads to end by default.

    • We also have another way to create threads
import threadingfrom threading import Threadclass MyThread(Thread):    def __init__(self, x):        super().__init__()        self.x = x    def run(self):        print('this is {}'.format(self.x))        time.sleep(2)def get_thread1(number=5):    l_thread = (MyThread(i) for i in range(number))    for t in l_thread:        print(t.name)        t.start()    print(len(threading.enumerate()))if __name__ == '__main__':    get_thread1(5)

The thread object has a run method, which is the target function that we need to execute, so we can override the Run method by inheriting the thread object and place our target code in the Run method.

Thread Object Analysis
class Thread:    def __init__(self, group=None, target=None, name=None,                 args=(), kwargs=None, *, daemon=None):        pass# Thread类是python用来创建线程的类,group:扩展保留字段;target:目标代码,一般是我们需要创建线程执行的目标函数。name:线程的名字,如果不指定会自动分配一个;args:目标函数的普通参数;kwargs:目标函数的键值对参数;daemon:设置线程是否为守护线程,即是前台执行还是后台执行,默认是非守护线程,当daemon=True时,子线程为守护线程,此时主线程不会等待子线程,如果主线程完成会强制杀死所有的子线程然后退出。# 方法start():创建一个子线程并执行,该方法一个Thread实例只能执行一次,其会创建一个线程执行该类的run方法。run():子线程需要执行的代码;join():主线程阻塞等待子线程直到子线程结束才继续执行,可以设置等待超时时间timeout.ident():线程标识符,线程未启动之前为None,启动后为一个int;is_alive():查看子线程是否还活着你返回一个布尔值。daemon:判断是否是守护线程;
Thread non-security and lock

Resources such as memory can be shared between multiple threads, allowing multiple threads to operate on the same resource, potentially causing the resource to break, that is, the thread is not secure.

number = 100class MyThread(Thread):    def run(self):        for i in range(1000000):            global number            number += 1        print(number)def get_thread1(number=5):    l_thread = (MyThread() for i in range(number))    for t in l_thread:        t.start()if __name__ == '__main__':    get_thread1(5)# 结果14394261378835224106025331503533150

The above example shows that if it is a synchronous operation, the result of the final number should be 5000100, but obviously not. The reason is that if thread 1 gets number=100, the thread switches to thread 2, gets number=100, plus 1 assigns to number=101, and if, switches back to thread 1,number plus 1 is 101, which is equivalent to two plus 1 operations, but number= 101. This is multithreaded thread non-security!

How to solve this problem? We see in the code above that number + + 1 is the core code, this place arbitrary switch threads will cause data corruption, so as long as we can set the code every time we execute here is not allowed to switch threads. This is the origin of the lock.

Add the above code with a lock:

number = 100mutex = threading.Lock() # 创建锁对象class MyThread(Thread):    def run(self):        global number        for i in range(1000000):            y = mutex.acquire() # 获取锁            if y: # 拿到锁就执行下面                number += 1                mutex.release() # 释放锁        print(number)def get_thread1(number=5):    l_thread = (MyThread() for i in range(number))    for t in l_thread:        t.start()if __name__ == '__main__':    get_thread1(5)# 结果:44811774742053486941349737715000100

The final result is expected, the threading module defines the lock class, can be very convenient to implement the lock mechanism, each time the core code to obtain the lock, get the ability to execute, can not get the default blocking wait.

#创建锁mutex = threading.Lock()#锁定mutex.acquire(blocking=True) # blocking=True,默认线程阻塞等待;如果blocking=False,线程不会等待,即上例中y会返回False,继续执行下面的代码,最后的结果不会符合预期#释放mutex.release()
    • Summary :
    1. After the locking, the locked code becomes a single thread, which prevents multi-threaded concurrency and decreases the efficiency.

    2. Locks can have multiple, if different threads hold different locks and wait for each other, it will cause a deadlock;

    3. Python's multithreading problem is far more than that, there is a legacy issue-global lock.

Dead lock

If there are two locks in a piece of code, a deadlock may occur and the system will die if a deadlock occurs.

number = 100mutex1 = threading.Lock() # 创建锁对象mutex2 = threading.Lock()class MyThread1(Thread):    def run(self):        global number        for i in range(1000):            if mutex1.acquire(): # 拿到锁就执行下面                number += 1                if mutex2.acquire():                    print('this is mutex2')                    mutex2.release()                mutex1.release() # 释放锁        print(number)class MyThread2(Thread):    def run(self):        global number        for i in range(1000):            if mutex2.acquire(): # 拿到锁就执行下面                number += 1                if mutex1.acquire():                    print('this is mutex2')                    mutex1.release()                mutex2.release() # 释放锁        print(number)def get_thread1():    l_thread = (MyThread1(), MyThread2())    for t in l_thread:        t.start()if __name__ == '__main__':    get_thread1()

A general workaround for deadlocks is to try not to use multiple locks, or to avoid deadlocks when designing programs, or to add timeout waits for locks.

Global Lock (GIL)

Global Lock the past life is not one or two words can be finished. Refer to: Python Global interpreter lock

A summary is:

    1. The existence of global lock is to protect the secure access of multithreading to data;
    2. For any Python program, no matter how many processor cores there are, there is always only one thread executing at any time;
    3. The existence of the global lock makes multithreading slower than single-threaded execution in general;
    4. Python program only in the IO-intensive multi-threaded code efficiency has improved, so the use of multithreading is not recommended, but more processes;
number = 100number1 = 100mutex = threading.Lock()class MyThread(Thread):    def run(self):        global number        t1 = time.time()        for i in range(1000000):            y = mutex.acquire() # 获取锁            if y: # 拿到锁就执行下面                number += 1                mutex.release() # 释放锁        t2 = time.time()        print(t2-t1)def get_thread1(number=5):    l_thread = (MyThread() for i in range(number))    for t in l_thread:        t.start()def get_thread2(n=5):    global number1    for i in range(1000000*n):        number1 += 1    print(number1)if __name__ == '__main__':    get_thread1()    t2 = time.time()    get_thread2()    t3 = time.time()    print(t3-t2)

Multi-threaded execution time is much larger than single thread.

Conclusion
    • Python is best to avoid multi-threading, instead of multithreading using multiple processes;

    • The co-process is a good alternative to multithreading.

Reference:

    • docs.python.org/

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.