First, the concept of lock.
Locks, which are commonly used to implement shared data access, create a lock object for each shared data (a lock), and when it is necessary to access this shared resource, the acquire method can be called to obtain a lock object when the shared resource access is finished and the release method is called to unlock.
Second, the mutex in Python.
Before introducing the mutex, let's take a look at an example. (one-1 operation per thread for num)
Import threading
Import time
num = #每个线程都共享这个变量.
Tread_list = []
Def count_num ():
Global num #每个线程都去获取这个全局变量.
Temp_num = num
Time.sleep (0.1) #执行sleep, equivalent to performing IO operations.
num = temp_num-1 #对公共的变量做一个-1 operation.
For I in range: #同时开启200个线程
t = Threading. Thread (Target=add_num)
T.start ()
Tread_list.append (t)
For T in Tread_list:
T.join ()
Print "Ending....num =%s"% (num)
The final result is:
Ending....num = 199
The result is not what we want. To analyze why this behavior occurs.
200 threads now want to uniformly modify a global variable, due to the Python interpreter's Gil lock limit, only one thread can run on the CPU at a time, when the execution to sleep is equivalent to an I/O operation, then it will be cut to other threads, before performing sleep, Currently running this thread, the thread takes the value of the global variable (temp_num = 200), before the time to make changes, it was switched to other threads, other threads are the same reason, take Temp_num = 200 This value, not yet time to calculate, Execution to sleep triggered an IO operation, and then cut to another thread, 2nd 3rd until the last thread has temp_num=200 this variable, the subsequent calculation operation will start to run! (Don't forget a concept that the thread will save the current execution state before it switches) when all the threads get the emp_num=200 variable, each thread executes it itself.
num = Temp_num-1 This also causes each thread to execute 200-1, so the final result is equal to 199.
Example 2. Also take the subtraction procedure just written for example, we shorten the sleep time to 0.001 seconds to see what will happen?
Or the last piece of code, just change the Count_num function's Time.sleep (0.1) to Time.sleep (0.001) to see what happens.
We also output the execution process:
I am Thread-1, set num 200
I am Thread-2, set num 200
I am Thread-3, set num 200
I am Thread-4, set num 200
I am Thread-5, set num 200
I am Thread-6, set num 200
I am Thread-7, set num 200
I am Thread-8, set num 200
I am Thread-9, set num 200
I am Thread-10, set num 200
I am Thread-11, set num 199
I am Thread-12, set num 199
I am Thread-13, set num 198
I am Thread-14, set num 198
I am Thread-15, set num 197
I am Thread-16, set num 197
I am THREAD-17, set num 197
I am Thread-18, set num 197
I am Thread-19, set num 196
I am Thread-20, set num 196
I am Thread-21, set num 196
I am Thread-22, set num 195
I am Thread-23, set num 195
I am Thread-24, set num 194
I am Thread-25, set num 194
I am Thread-26, set num 194
I am Thread-27, set num 193
I am Thread-28, set num 193
I am Thread-29, set num 192
I am Thread-30, set num 192
I am Thread-31, set num 192
I am Thread-32, set num 191
I am Thread-33, set num 190
I am Thread-34, set num 189
I am Thread-35, set num 189
I am Thread-36, set num 188
I am Thread-37, set num 187
I am Thread-38, set num 186
I am Thread-39, set num 186
I am Thread-40, set num 185
I am Thread-41, set num 185
I am Thread-42, set num 184
I am Thread-43, set num 184
I am Thread-44, set num 184
I am Thread-45, set num 184
I am Thread-46, set num 184
I am Thread-47, set num 183
I am Thread-48, set num 182
I am Thread-49, set num 182
I am Thread-50, set num 181
I am Thread-51, set num 179
I am Thread-52, set num 179
I am Thread-53, set num 179
I am Thread-54, set num 179
I am Thread-55, set num 177
I am Thread-56, set num 177
I am Thread-57, set num 177
I am Thread-58, set num 177
I am Thread-59, set num 177
I am Thread-60, set num 176
I am Thread-61, set num 175
I am Thread-62, set num 175
I am Thread-63, set num 174
I am Thread-64, set num 174
I am Thread-65, set num 174
I am Thread-66, set num 174
I am Thread-67, set num 173
I am Thread-68, set num 171
I am Thread-69, set num 171
I am Thread-70, set num 171
I am Thread-71, set num 170
I am Thread-72, set num 169
I am Thread-73, set num 168
I am Thread-74, set num 167
I am Thread-75, set num 166
I am Thread-76, set num 166
I am Thread-77, set num 165
I am Thread-78, set num 165
I am Thread-79, set num 165
I am Thread-80, set num 165
I am Thread-81, set num 164
I am Thread-82, set num 164
I am Thread-83, set num 163
I am Thread-84, set num 162
I am Thread-85, set num 162
I am Thread-86, set num 162
I am Thread-87, set num 160
I am Thread-88, set num 159
I am Thread-89, set num 159
I am Thread-90, set num 158
I am Thread-91, set num 157
I am Thread-92, set num 156
I am Thread-93, set num 156
I am Thread-94, set num 156
I am Thread-95, set num 156
I am Thread-96, set num 156
I am Thread-97, set num 155
I am Thread-98, set num 154
I am Thread-99, set num 154
I am Thread-100, set num 154
I am Thread-101, set num 153
I am Thread-102, set num 152
I am Thread-103, set num 152
I am Thread-104, set num 151
I am Thread-105, set num 151
I am Thread-106, set num 151
I am Thread-107, set num 151
I am Thread-108, set num 150
I am Thread-109, set num 149
I am Thread-110, set num 149
I am Thread-111, set num 149
I am Thread-112, set num 149
I am Thread-113, set num 149
I am Thread-114, set num 149
I am Thread-115, set num 149
I am Thread-116, set num 149
I am Thread-117, set num 149
I am Thread-118, set num 149
I am Thread-119, set num 149
I am Thread-120, set num 149
I am Thread-121, set num 149
I am Thread-122, set num 149
I am Thread-123, set num 148
I am Thread-124, set num 147
I am Thread-125, set num 147
I am Thread-126, set num 145
I am Thread-127, set num 145
I am Thread-128, set num 145
I am Thread-129, set num 144
I am Thread-130, set num 143
I am Thread-131, set num 142
I am Thread-132, set num 142
I am Thread-133, set num 142
I am Thread-134, set num 142
I am Thread-135, set num 142
I am Thread-136, set num 142
I am Thread-137, set num 141
I am Thread-138, set num 141
I am Thread-139, set num 141
I am Thread-140, set num 140
I am Thread-141, set num 140
I am Thread-142, set num 139
I am Thread-143, set num 139
I am Thread-144, set num 139
I am Thread-145, set num 139
I am Thread-146, set num 138
I am Thread-147, set num 138
I am Thread-148, set num 137
I am Thread-149, set num 136
I am Thread-150, set num 136
I am Thread-151, set num 136
I am Thread-152, set num 136
I am Thread-153, set num 136
I am Thread-154, set num 135
I am Thread-155, set num 135
I am Thread-156, set num 135
I am Thread-157, set num 134
I am Thread-158, set num 133
I am Thread-159, set num 133
I am Thread-160, set num 133
I am Thread-161, set num 133
I am Thread-162, set num 132
I am Thread-163, set num 131
I am Thread-164, set num 131
I am Thread-165, set num 131
I am Thread-166, set num 131
I am Thread-167, set num 131
I am Thread-168, set num 130
I am Thread-169, set num 130
I am Thread-170, set num 130
I am Thread-171, set num 130
I am Thread-172, set num 129
I am Thread-173, set num 127
I am Thread-174, set num 127
I am Thread-175, set num 127
I am Thread-176, set num 127
I am Thread-177, set num 127
I am Thread-178, set num 126
I am Thread-179, set num 126
I am Thread-180, set num 125
I am Thread-181, set num 124
I am Thread-182, set num 124
I am Thread-183, set num 124
I am Thread-184, set num 124
I am Thread-185, set num 123
I am Thread-186, set num 122
I am Thread-187, set num 122
I am Thread-188, set num 122
I am Thread-189, set num 122
I am Thread-190, set num 122
I am Thread-191, set num 121
I am Thread-192, set num 120
I am Thread-193, set num 119
I am Thread-194, set num 118
I am Thread-195, set num 118
I am Thread-196, set num 118
I am Thread-197, set num 118
I am Thread-198, set num 118
I am Thread-199, set num 117
I am Thread-200, set num 116
Ending....num = 115
The result was completely unexpected and eventually Num became 115.
Then analyze the cause of this result.
When the sleep time is short, during the process of thread switching, the sleep of the previously running threads is finished and will be re-engaged in competing CPU resources, and in the process of cutting, the previous thread sleep ends, there is the possibility of being cut back, continue to execute the following num = Temp_num -1 so that will lead to this situation.
Attention!! The sleep inside is used to simulate I/O operations in the program!
From the second example, we can see that a global resource is preempted, there is no control over the access control of a global resource by multiple threads, and the damage to global resources (where the damage refers to the result we do not want) makes it impossible to predict the results of the final execution of the program, and if we want to avoid this problem, we need to use " Mutex lock.
The main purpose of the mutex is to ensure the integrity of the shared data when the data is shared.
A mutex is implemented by creating a lock object for each shared resource, which is called when the shared resource needs to be accessed.
This locks the acquire method to get the lock object, and after the resource access is finished, the release method is called to unlock.
We have to rectify the above program, we need to add a mutex variable T_lock = threading. Lock (), and then we will preempt this lock t_lock.acquire () before we scramble for resources, and we release this lock T_lock.release () after the use of the resource is complete.
#!/usr/local/bin/python2.7
#-*-Coding:utf-8-*-
Import threading
Import time
num = 1000
Tread_list = []
T_lock = Threading. Rlock () #创建一个锁的对象.
Def add_num ():
Global Num,temp_num
If T_lock.acquire (): #加锁
Temp_num = num
Time.sleep (0.001) #执行sleep, equivalent to performing IO operations.
num = temp_num-1
T_lock.release () #公共资源访问和操作结束后, unlocking.
For I in range (200):
t = Threading. Thread (Target=add_num)
T.start ()
Tread_list.append (t)
For T in Tread_list:
T.join ()
Print "Ending....num =%s"% (num)
Finally, we look at the results of the output:
Ending....num = 0
Previous resource preemption has been addressed.
When a thread calls the acquire () method of a lock object to get a lock, the lock enters a state of "locked" lock, where only one thread can get the lock at a time, and if a second thread tries to acquire a lock (to access the operation's shared resources), To manipulate the shared data, the second thread will go into a blocking state until thread 1 is finished with the shared data resource operation, and after the call to the lock object's release method (where the lock has changed to "unlocked" state), thread two can then operate the shared resource.
The approximate lock-up idea is this:
Import threading
R=threading. Lock () #创建一个锁的对象
R.acquire () #加锁
‘‘‘
Operation of public data #执行了对公共数据的操作后
‘‘‘
R.release () #解锁
Last Additions ~
Written here, there may be people who think that mutexes and joins are no different!! That's not the case!
The mutex can be done only when the public data is accessed or manipulated in serial mode!
If a join is used, all operations performed in two threads will become serial mode!!
There's a big difference between the two!
This article is from the "Rebirth" blog, make sure to keep this source http://suhaozhi.blog.51cto.com/7272298/1924938
11.python Concurrency Primer (part3 Multi-threaded and mutex)