Talking about Python multithreading and program lock

Multithreading in Python uses the Threading module. The main class used in the Threading module is Thread. Let's write a simple multi-threaded code first:

# coding : uft-8
__ author__ ='Phtih0n'import threading

classMyThread(threading.Thread):
 def __init__(self):
  threading.Thread.__init__(self)

 def run(self):
  global n
  print n
  n +=1if"__main__"== __name__:
 n =0
 ThreadList =[]for i inrange(0,10):
  t =MyThread()
  ThreadList.append(t)for t in ThreadList:
  t.start()for t in ThreadList:
  t.join

The most common small example of multithreading. Let me talk about it briefly, I created a subclass MyThread that inherits the Thread class as our thread startup class. According to the regulations, rewrite the run method of Thread, and this method will be called automatically after our thread is started. So I first created 10 threads and added them to the list. Use another for loop to start each thread. When using a for loop, call the join method to wait for the end of all threads before exiting the main thread.

This code seems simple, but it actually hides a big problem, but it is not reflected here. Do you really think that I created 10 threads and called these 10 threads in sequence. Each thread adds 1 to n. In fact, it is possible that thread A executes n++, then thread C executes n++, and then The B thread executes n++.

This involves a "lock" problem. If there are multiple threads operating an object at the same time, if the object is not well protected, the results of the program will be unexpected (for example, we add a time to the run method of each thread .sleep(1), and output the thread name at the same time, we will find that the output will be messy. Because maybe one of our print statements only prints half of the characters, this thread will be suspended and the execution of another one will go, so we see The result is very messy), this phenomenon is called "thread insecurity":

Therefore, the Threading module provides us with a class, Threading.Lock, lock. We create an object of this type, "preempt" the lock before the thread function is executed, and "release" the lock after the execution is completed, then we ensure that only one thread holds the lock at a time. At this time, when operating on a public object, thread insecurity will not occur.

Therefore, we changed the code as follows:

# coding : uft-8
__ author__ ='Phtih0n'import threading, time

classMyThread(threading.Thread):
 def __init__(self):
  threading.Thread.__init__(self)

 def run(self):
  global n, lock
  time.sleep(1)if lock.acquire():
   print n , self.name
   n +=1
   lock.release()if"__main__"== __name__:
 n =1
 ThreadList =[]
 lock = threading.Lock()for i inrange(1,200):
  t =MyThread()
  ThreadList.append(t)for t in ThreadList:
  t.start()for t in ThreadList:
  t.join()

The final execution result:

We see that we first created a threading.Lock class object lock, in the run method, we used lock.acquire() to obtain the lock. At this time, other threads can no longer acquire the lock, and they will block in "if lock.acquire()" until the lock is released by another thread: lock.release().

Therefore, the content of the if statement is a complete piece of code, and there is no longer a situation where the execution of half of it is suspended to execute other threads. So the final result is neat.

Just like in Java, we use the synchronized keyword to decorate a method. The purpose is to make a certain piece of code executed by one thread without interruption and jumping to another thread.

This is the case when multiple threads occupy a common object. If multiple threads want to call multiple phenomena, and the A thread calls the A lock to occupy the A object, the B thread calls the B lock to occupy the B object, the A thread cannot call the B object, and the B thread cannot call the A object, so it has been waiting. This causes the thread "deadlock".

In the Threading module, there is also a class, RLock, called reentrant lock. The lock object maintains a Lock and a counter object internally. The counter object records the number of acquires, so that the resource can be acquired multiple times. Finally, when all RLocks are released, other threads can obtain resources. In the same thread, RLock.acquire can be called multiple times. With this feature, part of the deadlock problem can be solved.

The deadlock problem is very complicated, and over the years people have come up with many algorithms to solve it. I won't say more, you still need to refer to the help file.

Recommended Posts

Talking about Python multithreading and program lock
Talking about Python coroutine
Talking about Python functional programming
Talking about strings in Python
Talking about php calling python files
Talking about the modules in Python
Python multithreading
Python multithreading
Python and Go
Python introspection and reflection
[python] python2 and python3 under ubuntu
Learn about Python3 coroutine
Python3 configuration and entry.md