一、同步锁

1.1 多个线程抢占资源的情况

from threading import Thread
import os,time
def work():
global n
temp=n
time.sleep(0.1)
n=temp-1
if __name__ == '__main__':
n=100
l=[]
for i in range(100):
p=Thread(target=work)
l.append(p)
p.start()
for p in l:
p.join() print(n) #结果可能为99

1.1.1 对公共数据的操作

import threading
R=threading.Lock()
R.acquire()
'''
对公共数据的操作
'''
R.release()

1.2 同步锁的引用

from threading import Thread,Lock
import os,time
def work():
global n
lock.acquire()
temp=n
time.sleep(0.1)
n=temp-1
lock.release()
if __name__ == '__main__':
lock=Lock()
n=100
l=[]
for i in range(100):
p=Thread(target=work)
l.append(p)
p.start()
for p in l:
p.join() print(n) #结果肯定为0,由原来的并发执行变成串行,牺牲了执行效率保证了数据安全

1.3 互斥锁与join的区别

#不加锁:并发执行,速度快,数据不安全
from threading import current_thread,Thread,Lock
import os,time
def task():
global n
print('%s is running' %current_thread().getName())
temp=n
time.sleep(0.5)
n=temp-1 if __name__ == '__main__':
n=100
lock=Lock()
threads=[]
start_time=time.time()
for i in range(100):
t=Thread(target=task)
threads.append(t)
t.start()
for t in threads:
t.join() stop_time=time.time()
print('主:%s n:%s' %(stop_time-start_time,n)) '''
Thread-1 is running
Thread-2 is running
......
Thread-100 is running
主:0.5216062068939209 n:99
''' #不加锁:未加锁部分并发执行,加锁部分串行执行,速度慢,数据安全
from threading import current_thread,Thread,Lock
import os,time
def task():
#未加锁的代码并发运行
time.sleep(3)
print('%s start to run' %current_thread().getName())
global n
#加锁的代码串行运行
lock.acquire()
temp=n
time.sleep(0.5)
n=temp-1
lock.release() if __name__ == '__main__':
n=100
lock=Lock()
threads=[]
start_time=time.time()
for i in range(100):
t=Thread(target=task)
threads.append(t)
t.start()
for t in threads:
t.join()
stop_time=time.time()
print('主:%s n:%s' %(stop_time-start_time,n)) '''
Thread-1 is running
Thread-2 is running
......
Thread-100 is running
主:53.294203758239746 n:0
''' # 有的同学可能有疑问:既然加锁会让运行变成串行,那么我在start之后立即使用join,就不用加锁了啊,也是串行的效果啊 # 没错:在start之后立刻使用jion,肯定会将100个任务的执行变成串行,毫无疑问,最终n的结果也肯定是0,是安全的,但问题是 # start后立即join:任务内的所有代码都是串行执行的,而加锁,只是加锁的部分即修改共享数据的部分是串行的 # 单从保证数据安全方面,二者都可以实现,但很明显是加锁的效率更高.
from threading import current_thread,Thread,Lock
import os,time
def task():
time.sleep(3)
print('%s start to run' %current_thread().getName())
global n
temp=n
time.sleep(0.5)
n=temp-1 if __name__ == '__main__':
n=100
lock=Lock()
start_time=time.time()
for i in range(100):
t=Thread(target=task)
t.start()
t.join()
stop_time=time.time()
print('主:%s n:%s' %(stop_time-start_time,n)) '''
Thread-1 start to run
Thread-2 start to run
......
Thread-100 start to run
主:350.6937336921692 n:0 #耗时是多么的恐怖
''' )

二、死锁与递归锁

进程也有死锁与递归锁,在进程那里忘记说了,放到这里一起说了。

所谓死锁:是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁

2.1 死锁

from threading import Lock as Lock
import time
mutexA=Lock()
mutexA.acquire()
mutexA.acquire()
print(123)
mutexA.release()
mutexA.release()

解决方法:递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。

这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁。

2.2 递归锁RLock

from threading import RLock as Lock
import time
mutexA=Lock()
mutexA.acquire()
mutexA.acquire()
print(123)
mutexA.release()
mutexA.release()

三、典型问题:科学家吃面

3.1 死锁问题

import time
from threading import Thread,Lock
noodle_lock = Lock()
fork_lock = Lock()
def eat1(name):
noodle_lock.acquire()
print('%s 抢到了面条'%name)
fork_lock.acquire()
print('%s 抢到了叉子'%name)
print('%s 吃面'%name)
fork_lock.release()
noodle_lock.release() def eat2(name):
fork_lock.acquire()
print('%s 抢到了叉子' % name)
time.sleep(1)
noodle_lock.acquire()
print('%s 抢到了面条' % name)
print('%s 吃面' % name)
noodle_lock.release()
fork_lock.release() for name in ['哪吒','nick','tank']:
t1 = Thread(target=eat1,args=(name,))
t2 = Thread(target=eat2,args=(name,))
t1.start()
t2.start()

3.2 递归锁解决死锁问题

import time
from threading import Thread,RLock
fork_lock = noodle_lock = RLock()
def eat1(name):
noodle_lock.acquire()
print('%s 抢到了面条'%name)
fork_lock.acquire()
print('%s 抢到了叉子'%name)
print('%s 吃面'%name)
fork_lock.release()
noodle_lock.release() def eat2(name):
fork_lock.acquire()
print('%s 抢到了叉子' % name)
time.sleep(1)
noodle_lock.acquire()
print('%s 抢到了面条' % name)
print('%s 吃面' % name)
noodle_lock.release()
fork_lock.release() for name in ['哪吒','nick','tank']:
t1 = Thread(target=eat1,args=(name,))
t2 = Thread(target=eat2,args=(name,))
t1.start()
t2.start()

Python程序中的线程操作-锁的更多相关文章

  1. Python程序中的线程操作(线程池)-concurrent模块

    目录 Python程序中的线程操作(线程池)-concurrent模块 一.Python标准模块--concurrent.futures 二.介绍 三.基本方法 四.ProcessPoolExecut ...

  2. 30、Python程序中的线程操作(oncurrent模块)

    进程是cpu资源分配的最小单元,一个进程中可以有多个线程. 线程是cpu计算的最小单元. 对于Python来说他的进程和线程和其他语言有差异,是有GIL锁. GIL锁 GIL锁保证一个进程中同一时刻只 ...

  3. Python程序中的线程操作-创建多线程

    目录 一.python线程模块的选择 二.threading模块 三.通过threading.Thread类创建线程 3.1 创建线程的方式一 3.2 创建线程的方式二 四.多线程与多进程 4.1 p ...

  4. Python程序中的线程操作-concurrent模块

    目录 一.Python标准模块--concurrent.futures 二.介绍 三.基本方法 四.ProcessPoolExecutor 五.ThreadPoolExecutor 六.map的用法 ...

  5. Python程序中的线程操作-守护线程

    目录 一.守护线程 1.1 详细解释 1.2 守护线程例1 1.3 守护线程例2 一.守护线程 无论是进程还是线程,都遵循:守护xx会等待主xx运行完毕后被销毁.需要强调的是:运行完毕并非终止运行. ...

  6. Python程序中的线程操作-线程队列

    目录 一.线程队列 二.先进先出 三.后进先出 四.存储数据时可设置优先级的队列 4.1 优先级队列 4.2 更多方法说明 一.线程队列 queue队列:使用import queue,用法与进程Que ...

  7. 在Python程序中的进程操作,multiprocess.Process模块

    在python程序中的进程操作 之前我们已经了解了很多进程相关的理论知识,了解进程是什么应该不再困难了,刚刚我们已经了解了,运行中的程序就是一个进程.所有的进程都是通过它的父进程来创建的.因此,运行起 ...

  8. python 全栈开发,Day38(在python程序中的进程操作,multiprocess.Process模块)

    昨日内容回顾 操作系统纸带打孔计算机批处理 —— 磁带 联机 脱机多道操作系统 —— 极大的提高了CPU的利用率 在计算机中 可以有超过一个进程 进程遇到IO的时候 切换给另外的进程使用CPU 数据隔 ...

  9. Python程序中的进程操作--—--开启多进程

    Python程序中的进程操作-----开启多进程 之前我们已经了解了很多进程相关的理论知识,了解进程是什么应该不再困难了,刚刚我们已经了解了,运行中的程序就是一个进程.所有的进程都是通过它的父进程来创 ...

随机推荐

  1. JSP的介绍

    JSP概念 JSP全称java server page,中文含义为java服务端页面.对于jsp的理解需要和另外几个相似的概念连接起来:Html和Servlet.常规的html作为一个静态文本传输,具 ...

  2. 2018年Code Review状态报告

    Code Review 代码评审是指在软件开发过程中,对源代码的系统性检查.通常的目的是查找系统缺陷,保证软件总体质量和提高开发者自身水平. Code Review是轻量级代码评审,相对于正式代码评审 ...

  3. js中自执行函数(function(){})()和(function(){}())区别

    方式一,调用函数,得到返回值.强制函数直接量执行再返回一个引用,引用在去调用执行方式二,调用函数,得到返回值.强制运算符使函数调用执行(function(){})(); 是 把函数当作表达式解析,然后 ...

  4. 25.md5 collision(NUPT_CTF)

    抓住两点提示: 1.md5碰撞 2.please input a 利用0 == 字符串是成立的,从而可以绕过MD5检查. 所以找一个md5是0e开头的值,因为 php 在处理 == 的时候当碰到的字符 ...

  5. Codeforces Round #607 (Div. 1)

    A. Cut and Paste 题解 在计算答案的时候,我们发现只需要知道这个字符串前\(l\) 个具体是啥就行了.所以对于每一组询问,我们暴力把这个字符串前\(l\) 的位都算出来,然后剩下的就推 ...

  6. Notepad++ 异常崩溃 未保存的new *文件列表没了怎么办?

    今天就遇到这种问题了,把之前写的临时代码拷贝到Notepad++,不知道啥时候脑袋一抽风强迫症犯了就把所有临时代码给未保存关闭了,然后懊恼不已,百度了一下解决办法,一下就搜到了. Notepad++是 ...

  7. Java实现网络聊天中使用的socket API与Linux socket API之间的关系

    尝试着用Java编写一个网络聊天程序,发现总不如网上写的好,所以就直接引用了网上大神的优秀代码.代码如下: package project1; import java.awt.*; import ja ...

  8. HTML中跨域请求天气粗略效果

    HTML中跨域请求天气粗略效果 html+css部分: <style> table{ border:1px red solid; border-collapse: collapse; ma ...

  9. C sharp #004# 进度条与Timer

    饮水思源:金老师的自学网站 C#实现进度条异常简单,因为所有东西都已经封装好了. 只需要简单的拖拽: 写两行代码就完工了: private void timer1_Tick(object sender ...

  10. Django入门必知必会操作

    一.Django基础必备三件套 HttpRseponse 内部传入一个字符串参数,返回给浏览器. 在app目录下的views.py添加函数,添加函数之前必须在urls.py添加函数对应关系,否则访问不 ...