代码拉取完成,页面将自动刷新
# 1,简述线程和协程的异同?
# 协程比线程更小的执行单元(微线程)
#一个线程作为一个容器里面可以放置多个协程
# 只切换函数调用即可完成多线程,可以减少CPU的切换
# 协程自己主动让出CPU
# 线程的任务切换是由操作系统自行切换的,
# 协程可以通过自己的程序来进行切换
# 2,什么是并行,什么是并发?
# 并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
# 并行是在不同实体上的多个事件,并发是在同一实体上的多个事件
# 在一台处理器上“同时”(这个同时实际上市交替“”)处理多个任务,在多台处理器上同时处理多个任务。如hadoop分布式集群
# 3,请解释同步和异步这两个概念?
# 同步意味着顺序、统一的时间轴
# 场景1:是指完成事务的逻辑,先执行第一个事务,如果阻塞了,会一直等待,
# 直到这个事务完成,再执行第二个事务,协同步调,按预定的先后次序进行运行
# 场景2:一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,
# 依赖的任务才能算完成,这是一种可靠的任务序列
# 处理调用这个事务的之后,不会等待这个事务的处理结果,直接处理第二个事务去了,通过状态
# 、回调来通知调用者处理结果
# 对于I/O相关的程序来说,异步编程可以大幅度的提高系统的吞吐量,
# 因为在某个I/O操作的读写过程中,系统可以先去处理其它的操作(通常是其它的I/O操作)
# 不确定执行顺序
# 4,GIL锁是怎么回事?
# GIL全局解释器锁,Cpython独有的锁,牺牲效率保证数据安全
# Cpython在所有线程进入解释器之前加了一个全局解释器锁(GIL锁)。
# 这个锁是互斥锁,是加在解释器上的,导致同一时间只有一个线程在执行所以你用不了多核
# 5,什么叫死锁?如何产生?如何解决
# 所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。
# 二、死锁产生的原因
#
# 1) 系统资源的竞争
# 通常系统中拥有的不可剥夺资源,其数量不足以满足多个进程运行的需要,使得进程在 运行过程中,会因争夺资源而陷入僵局,如磁带机、打印机等。只有对不可剥夺资源的竞争 才可能产生死锁,对可剥夺资源的竞争是不会引起死锁的。
# 2) 进程推进顺序非法
# 进程在运行过程中,请求和释放资源的顺序不当,也同样会导致死锁。例如,并发进程 P1、P2分别保持了资源R1、R2,而进程P1申请资源R2,进程P2申请资源R1时,两者都 会因为所需资源被占用而阻塞。
# 3)信号量使用不当也会造成死锁。进程间彼此相互等待对方发来的消息,结果也会使得这 些进程间无法继续向前推进。例如,进程A等待进程B发的消息,进程B又在等待进程A 发的消息,可以看出进程A和B不是因为竞争同一资源,而是在等待对方的资源导致死锁。
# 4) 死锁产生的必要条件
#
# 产生死锁必须同时满足以下四个条件,只要其中任一条件不成立,死锁就不会发生。
# 互斥条件:进程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某 资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
# 不剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)。
# 请求和保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
# 循环等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被 链中下一个进程所请求。即存在一个处于等待状态的进程集合{Pl, P2, ..., pn},其中Pi等 待的资源被P(i+1)占有(i=0, 1, ..., n-1),Pn等待的资源被P0占有,如图2-15所示。
#
# 直观上看,循环等待条件似乎和死锁的定义一样,其实不然。按死锁定义构成等待环所 要求的条件更严,它要求Pi等待的资源必须由P(i+1)来满足,而循环等待条件则无此限制。 例如,系统中有两台输出设备,P0占有一台,PK占有另一台,且K不属于集合{0, 1, ..., n}。
#
# Pn等待一台输出设备,它可以从P0获得,也可能从PK获得。因此,虽然Pn、P0和其他 一些进程形成了循环等待圈,但PK不在圈内,若PK释放了输出设备,则可打破循环等待, 如图2-16所示。因此循环等待只是死锁的必要条件。
#
#
# 三、如何避免死锁
# 在有些情况下死锁是可以避免的。三种用于避免死锁的技术:
#
# 加锁顺序(线程按照一定的顺序加锁)
# 加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)
# 死锁检测
# 加锁顺序
#
# 当多个线程需要相同的一些锁,但是按照不同的顺序加锁,死锁就很容易发生。
#
# 如果能确保所有的线程都是按照相同的顺序获得锁,那么死锁就不会发生。
#
# 如果一个线程(比如线程3)需要一些锁,那么它必须按照确定的顺序获取锁。它只有获得了从顺序上排在前面的锁之后,才能获取后面的锁。
#
# 例如,线程2和线程3只有在获取了锁A之后才能尝试获取锁C(译者注:获取锁A是获取锁C的必要条件)。因为线程1已经拥有了锁A,所以线程2和3需要一直等到锁A被释放。然后在它们尝试对B或C加锁之前,必须成功地对A加了锁。
#
# 按照顺序加锁是一种有效的死锁预防机制。但是,这种方式需要你事先知道所有可能会用到的锁(译者注:并对这些锁做适当的排序),但总有些时候是无法预知的。
#
# 加锁时限
# 另外一个可以避免死锁的方法是在尝试获取锁的时候加一个超时时间,
# 这也就意味着在尝试获取锁的过程中若超过了这个时限该线程则放弃对该锁请求。
# 若一个线程没有在给定的时限内成功获得所有需要的锁,则会进行回退并释放所有已经获得的锁,
# 然后等待一段随机的时间再重试。这段随机的等待时间让其它线程有机会尝试获取相同的这些锁,
# 并且让该应用在没有获得锁的时候可以继续运行(加锁超时后可以先继续运行干点其它事情,再回头来重复之前加锁的逻辑)。
#
# 死锁检测
# 死锁检测是一个更好的死锁预防机制,它主要是针对那些不可能实现按序加锁并且锁超时也不可行的场景。
#
# 每当一个线程获得了锁,会在线程和锁相关的数据结构中(map、graph等等)将其记下。除此之外,每当有线程请求锁,也需要记录在这个数据结构中。
#
# 当一个线程请求锁失败时,这个线程可以遍历锁的关系图看看是否有死锁发生。例如,线程A请求锁7,但是锁7这个时候被线程B持有,这时线程A就可以检查一下线程B是否已经请求了线程A当前所持有的锁。如果线程B确实有这样的请求,那么就是发生了死锁(线程A拥有锁1,请求锁7;线程B拥有锁7,请求锁1)。
#
# 当然,死锁一般要比两个线程互相持有对方的锁这种情况要复杂的多。线程A等待线程B,线程B等待线程C,线程C等待线程D,线程D又在等待线程A。线程A为了检测死锁,它需要递进地检测所有被B请求的锁。从线程B所请求的锁开始,线程A找到了线程C,然后又找到了线程D,发现线程D请求的锁被线程A自己持有着。这是它就知道发生了死锁。
#
# 那么当检测出死锁时,这些线程该做些什么呢?
#
# 一个可行的做法是释放所有锁,回退,并且等待一段随机的时间后重试。这个和简单的加锁超时类似,不一样的是只有死锁已经发生了才回退,而不会是因为加锁的请求超时了。虽然有回退和等待,但是如果有大量的线程竞争同一批锁,它们还是会重复地死锁(原因同超时类似,不能从根本上减轻竞争)。
#
# 一个更好的方案是给这些线程设置优先级,让一个(或几个)线程回退,剩下的线程就像没发生死锁一样继续保持着它们需要的锁。如果赋予这些线程的优先级是固定不变的,同一批线程总是会拥有更高的优先级。为避免这个问题,可以在死锁发生的时候设置随机的优先级。
# 6,写一个程序,利用queue实现进程间通信;
# from multiprocessing import Process,Queue
# import time
# a =['a','b','c']
# def func(q):
# for i in a:
# print("开始写入",i)
# q.put(i)
# time.sleep(1)
#
#
# def func1(q):
# while True:
# if not q.empty():
# print("读取到的是",q.get())
# time.sleep(1)
# else:
# break
#
#
# if __name__ == '__main__':
# q =Queue()
# p1 =Process(target=func,args=(q,))
# p2 =Process(target=func1,args=(q,))
# p1.start()
# p1.join()#等待接收完毕
# p2.start()
# p2.join()
# print("接收完毕")
# 7,写一个程序,包含十个线程,同时只能有五个子线程并行执行
# import threading
# import time
# s1 =threading.Semaphore(5)
# def func():
# s1.acquire()
# time.sleep(2)
# print("ok")
# s1.release()
# for i in range(10):
# t =threading.Thread(target=func,args=())
# t.start()
# 8,写一个程序,线程C在线程B后执行,线程B在线程A之后进行
# import threading
# import time
# class Thread1(threading.Thread):
# def run(self):
# while True:
# if Lock1.acquire():
# print("--tAK---")
# time.sleep(1)
# Lock2.release()
#
# class Thread2(threading.Thread):
# def run(self):
# while True:
# if Lock2.acquire():
# print("__tak222___")
# time.sleep(2)
# Lock3.release()
# class Thread3(threading.Thread):
# def run(self):
# while True:
# if Lock3.acquire():
# print("__tak3333___")
# time.sleep(2)
# Lock1.release()
# Lock1 =threading.Lock()
# Lock2 =threading.Lock()
# Lock2.acquire()
# Lock3 =threading.Lock()
# Lock3.acquire()
# A =Thread1()
# B =Thread2()
#
# C =Thread3()
# A.start()
# B.start()
#
# C.start()
# 9,编写一个程序,开启3个线程,这3个线程的name分别为A、B、C,
# 每个线程将自己的name在屏幕上打印10遍,
# 要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推
import threading
import time
class Thread1(threading.Thread):
def run(self):
for i in range(10):
if Lock1.acquire():
print(threading.current_thread().name)
time.sleep(1)
Lock2.release()
class Thread2(threading.Thread):
def run(self):
for i in range(10):
if Lock2.acquire():
print(threading.current_thread().name)
time.sleep(1)
Lock3.release()
class Thread3(threading.Thread):
def run(self):
for i in range(10):
if Lock3.acquire():
print(threading.current_thread().name)
time.sleep(1)
Lock1.release()
Lock1 = threading.Lock()
Lock2 = threading.Lock()
Lock2.acquire()
Lock3 = threading.Lock()
Lock3.acquire()
A = Thread1()
B = Thread2()
C = Thread3()
A.start()
B.start()
C.start()
# 10,简述生产者与消费者模式(用自己的话默写)
# ⽣产者消费者模式是通过⼀个容器(缓冲区)来解决⽣产者和消费者的强耦合问题
# ⽣产者和消费者彼此之间不直接通讯, ⽽通过阻塞队列来进⾏通讯
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。