Python: 睡眠线程的惩罚
这个问题是关于在一个网络服务器上,如果有很多处于休眠状态的Python线程,会不会影响性能。
背景:我正在用Django/Satchmo搭建一个在线商店。一个需求是支持延迟付款。顾客可以预定一个产品,并允许第三方在稍后的时间通过一个随机且唯一的链接来付款。
为了处理取消预定的情况,我创建了一个线程,它会在预定时间内休眠,等到醒来后再取消预定或将产品标记为已售出。代码大概是这样的:
#Reserves a product when it is placed in the cart
def reserve_cart_product(product):
log.debug("Reserving %s" % product.name)
product.active = False
product.featured = False
product.save()
from threading import Timer
Timer(CART_RESERVE_TIME, check_reservation, (product,)).start()
我在处理过期的唯一链接时也用同样的方法,只不过这个定时器的休眠时间要长得多(通常是5天)。
所以,我想问你们的是:
有很多处于休眠状态的线程会严重影响性能吗?有没有更好的方法来安排将来某个时间点发生的一次性事件?如果可以的话,我希望继续使用Python,不想通过sys
调用at
或cron
。
这个网站的流量并不算高;每周最多大约有100个产品被订购(这个数字是比较宽松的)。再加上购物车的预定,这可能意味着任何时候都有100多个线程在休眠。我会不会后悔用这种方式来安排任务呢?
谢谢
3 个回答
通常,处于休眠状态的线程除了占用一些内存(比如它们的栈和其他私有数据)外,不会带来额外的负担。现代操作系统的调度算法效率很高,复杂度是O(1),这意味着即使是正在运行的线程,也不会增加额外的开销,除了占用的内存空间。
同时,很难想象一个高效的设计需要很多线程。唯一能想到的情况是与许多其他伙伴进行通信。在这种情况下,应该使用异步输入输出(IO)。
100个线程没问题,但正如tgray提到的,如果服务器出现故障(比如停电、计划维护、硬件故障等)会发生什么呢?
你需要把未完成的预定信息存储在数据库里。
然后你可以设置一个定时任务,定期运行一个取消预定的脚本,这样就不需要让那么多线程一直在那儿待着。
如果你真的不想用定时任务,可以只用一个工作线程,让它每分钟休眠一次,然后检查是否有需要取消的预定。
我觉得这个应该没问题。Timer的底层代码(在threading.py里)其实就是用time.sleep来实现的。等了一段时间后,它基本上会运行一个循环,每次暂停0.05秒。这样的话,CPU的使用率几乎是0%,即使有几百个线程也是如此。下面是一个简单的例子,我在这个例子中观察到Python进程的CPU使用率是0%:
import threading
def nothing():
pass
def testThreads():
timers = [threading.Timer(10.0, nothing) for _ in xrange(881)]
print "Starting threads."
map(threading.Thread.start, timers)
print "Joining threads."
map(threading.Thread.join, timers)
print "Done."
if __name__ == "__main__":
testThreads()
真正的问题是,你可能无法启动太多线程。在我这个64位、4GB内存的系统上,我最多只能启动881个线程,超过这个数量就会出错。不过,如果你真的只需要几百个线程,我想应该是没问题的。