A. 这个python服务器为什么会触发超时,死锁还是阻塞怎么解决
死锁示例
搞多线程的经常会遇到死锁的问题,学习操作系统的时候会讲到死锁相关的东西,我们用Python直观的演示一下。
死锁的一个原因是互斥锁。假设银行系统中,用户a试图转账100块给用户b,与此同时用户b试图转账200块给用户a,则可能产生死锁。
2个线程互相等待对方的锁,互相占用着资源不释放。
#coding=utf-8
importtime
importthreading
classAccount:
def__init__(self,_id,balance,lock):
self.id=_id
self.balance=balance
self.lock=lock
defwithdraw(self,amount):
self.balance-=amount
defdeposit(self,amount):
self.balance+=amount
deftransfer(_from,to,amount):
if_from.lock.acquire():#锁住自己的账户
_from.withdraw(amount)
time.sleep(1)#让交易时间变长,2个交易线程时间上重叠,有足够时间来产生死锁
print'waitforlock...'
ifto.lock.acquire():#锁住对方的账户
to.deposit(amount)
to.lock.release()
_from.lock.release()
print'finish...'
a=Account('a',1000,threading.Lock())
b=Account('b',1000,threading.Lock())
threading.Thread(target=transfer,args=(a,b,100)).start()
threading.Thread(target=transfer,args=(b,a,200)).start()
防止死锁的加锁机制
问题:
你正在写一个多线程程序,其中线程需要一次获取多个锁,此时如何避免死锁问题。
解决方案:
在多线程程序中,死锁问题很大一部分是由于线程同时获取多个锁造成的。举个例子:一个线程获取了第一个锁,然后在获取第二个锁的 时候发生阻塞,那么这个线程就可能阻塞其他线程的执行,从而导致整个程序假死。 解决死锁问题的一种方案是为程序中的每一个锁分配一个唯一的id,然后只允许按照升序规则来使用多个锁,这个规则使用上下文管理器 是非常容易实现的,示例如下:
importthreading
#Thread-
_local=threading.local()
@contextmanager
defacquire(*locks):
#Sortlocksbyobjectidentifier
locks=sorted(locks,key=lambdax:id(x))
#
acquired=getattr(_local,'acquired',[])
ifacquiredandmax(id(lock)forlockinacquired)>=id(locks[0]):
raiseRuntimeError('LockOrderViolation')
#Acquireallofthelocks
acquired.extend(locks)
_local.acquired=acquired
try:
forlockinlocks:
lock.acquire()
yield
finally:
#
forlockinreversed(locks):
lock.release()
delacquired[-len(locks):]
B. 求助python多线程,执行到100多个停止了
python 线程 暂停, 恢复, 退出
我们都知道python中可以是threading模块实现多线程, 但是模块并没有提供暂停, 恢复和停止线程的方法, 一旦线程对象调用start方法后, 只能等到对应的方法函数运行完毕. 也就是说一旦start后, 线程就属于失控状态. 不过, 我们可以自己实现这些. 一般的方法就是循环地判断一个标志位, 一旦标志位到达到预定的值, 就退出循环. 这样就能做到退出线程了. 但暂停和恢复线程就有点难了, 我一直也不清除有什么好的方法, 直到我看到threading中Event对象的wait方法的描述时.
wait([timeout])
Block until the internal flag is true. If the internal flag is true on entry, return immediately. Otherwise, block until another thread calls set() to set the flag to true, or until the optional timeout occurs.
阻塞, 直到内部的标志位为True时. 如果在内部的标志位在进入时为True时, 立即返回. 否则, 阻塞直到其他线程调用set()方法将标准位设为True, 或者到达了可选的timeout时间.
When the timeout argument is present and not None, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof).
This method returns the internal flag on exit, so it will always return True except if a timeout is given and the operation times out.
当给定了timeout参数且不为None, 它应该是一个浮点数,以秒为单位指定操作的超时(或是分数)。
此方法在退出时返回内部标志,因此除非给定了超时且操作超时,否则它将始终返回True。
Changed in version 2.7: Previously, the method always returned None.
2.7版本以前, 这个方法总会返回None.
<br>
利用wait的阻塞机制, 就能够实现暂停和恢复了, 再配合循环判断标识位, 就能实现退出了, 下面是代码示例:
#!/usr/bin/env python
# coding: utf-8
import threading
import time
class Job(threading.Thread):
def __init__(self, *args, **kwargs):
super(Job, self).__init__(*args, **kwargs)
self.__flag = threading.Event() # 用于暂停线程的标识
self.__flag.set() # 设置为True
self.__running = threading.Event() # 用于停止线程的标识
self.__running.set() # 将running设置为True
def run(self):
while self.__running.isSet():
self.__flag.wait() # 为True时立即返回, 为False时阻塞直到内部的标识位为True后返回
print time.time()
time.sleep(1)
def pause(self):
self.__flag.clear() # 设置为False, 让线程阻塞
def resume(self):
self.__flag.set() # 设置为True, 让线程停止阻塞
def stop(self):
self.__flag.set() # 将线程从暂停状态恢复, 如何已经暂停的话
self.__running.clear() # 设置为False
下面是测试代码:
a = Job()
a.start()
time.sleep(3)
a.pause()
time.sleep(3)
a.resume()
time.sleep(3)
a.pause()
time.sleep(2)
a.stop()
<br>
测试的结果:
这完成了暂停, 恢复和停止的功能. 但是这里有一个缺点: 无论是暂停还是停止, 都不是瞬时的, 必须等待run函数内部的运行到达标志位判断时才有效. 也就是说操作会滞后一次.
但是这有时也不一定是坏事. 如果run函数中涉及了文件操作或数据库操作等, 完整地运行一次后再退出, 反而能够执行剩余的资源释放操作的代码(例如各种close). 不会出现程序的文件操作符超出上限, 数据库连接未释放等尴尬的情况.
C. python多线程中每个线程如果不加休眠时间就会只泡在一个线程上,这该如何处理谢谢
这是三个线程都在跑啊,只是并发的而已
D. python多线程运行过程中出现奇怪的等待行为
你这个程序问题在new = Thread( self.subfunc(i) ) 传进去的时候就已经调用了self.subfunc
改成 new = Thread( target=self.subfunc, args=(i,) )
另外i 数字太小也看不出来,因为工作量太小,在线程的一个时间片内函数就执行完了,看不到切换的过程,设成if i>10000就明显了
E. python多线程为什么会暂停一下,再接着跑 跑一段时间,会暂停几秒钟,然后接着打印。
线程之间的输出,需要在池中中转,死循环的时间长了,出现满栈的概率提高,外在表现就是卡一会儿
F. python3.7多线程代码不执行
使用多进程代替多线程
G. python 程序假死的问题
我遇到的这种现象常见在引用占用了大量的系统内存,
后来我将直接读入大量数据到内存的过程改为用iter读取, 现象没再出现.
你的方案"超过一定时间...", 可以视为"守护进程",
如果这个进程是你的应用内的某个线程, 恐怕它会一同"睡"去 :(
.. 还是先确认一下是否是内存占用的原因吧, 如果是通过节省内存的方式可以克服的.
H. python爬虫多线程假死怎么解决
如果是爬虫的话,这个一般都是由于网络原因造成的卡住,可以做两层控制:
在HTTP请求上设置好超时时间,最好设定sockect的超时,这样更底层一些。
在上层做一个检测机制,定时轮询线程是否正常,如果遇到不响应的直接kill掉。