2010-02-01 129 views
6

這個問題涉及到在web服務器上有大量睡眠python線程可能產生或可能不會產生的性能懲罰。Python:對於睡眠線程的懲罰

背景:我正在使用django/satchmo實施在線商店。要求延遲付款。客戶可以預訂產品並允許第三方在以後支付(通過隨機和唯一的URL)。

爲了處理不能保存的項目,我創建了一個線程,該線程將在預定時間內休眠,然後刪除保留/在產品醒來時標記產品。它看起來像這樣:

#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天)。

所以,我想問你的SO如下:

是具有大numnber睡眠的線程會嚴重影響性能?未來有沒有更好的技術來安排一次性事件。如果可能的話,我想保留在python中;沒有通過sys致電atcron

該網站是不完全高流量;每週訂購產品的(慷慨)上限約爲100.與購物車預訂相結合,這可能意味着任何時候都有100多條睡眠線程。我會後悔以這種方式安排任務嗎?

謝謝

+1

如果服務器出現故障,您可能需要一個比線程更持久的解決方案。據我所知,你必須搜索你的日誌文件,告訴哪些產品在崩潰後被保留(儘管你不知道它們被保留了多長時間以上代碼)。 – tgray 2010-02-01 20:37:24

+0

你說得很好,正因爲如此,我已經開始在數據庫中存儲一些記錄。 – pisswillis 2010-02-02 17:13:49

+0

你假設你的服務器不會重新啓動,並且你不會得到成千上萬的訂單,對吧?一個更強大的選項是一個持久的數據庫排隊系統,比如RabbitMQ。 – 2013-01-10 10:59:32

回答

7

我看不出爲什麼這不應該工作。 Timer(在threading.py中)的底層代碼只是使用time.sleep。一旦它等待一段時間,它就會基本上運行一個帶有time.sleep(0.05)的循環。即使有數百個線程,這也會導致CPU使用率基本爲0%。這裏有一個簡單的例子,在那裏我注意到0%CPU使用率蟒蛇過程:

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個線程。如果你真的只有幾百個,但我無法想象它不會起作用。

3

通常,睡眠線程除了分配給它們的堆棧和其他私有數據的內存之外沒有開銷。現代操作系統調度算法的複雜度爲O(1),所以即使正在運行的線程也不會引入開銷,而不是內存佔用。同時,很難想象高效的設計需要大量的線程。只有我能想象的情況是與其他許多同行進行溝通。在這種情況下 - 應該使用異步IO。

4

100個線程是沒有問題的,但是作爲tgray pointed out,如果服務器出現故障(停電,計劃維護,硬件故障等),會發生什麼情況?

您需要將未保存信息存儲在數據庫的某處。

然後你可以有一個cron作業週期性地觸發一個未保存的腳本,例如,你不需要讓所有這些線程都坐在這裏。

如果您真的不想使用cron,只需要一個工作線程休眠一分鐘,然後檢查是否有任何未保留的應用程序。