循环中"time.sleep"与"threading.Timer"的资源使用情况

Muh*_*aha 4 python memory multithreading timer python-2.7

第一种方法:

import threading
import time

def keepalive():
    while True:
        print 'Alive.'
        time.sleep(200)
threading.Thread(target=keepalive).start()
Run Code Online (Sandbox Code Playgroud)

第二种方法:

import threading

def keepalive():
    print 'Alive.'
    threading.Timer(200, keepalive).start()

threading.Timer(200, keepalive).start()
Run Code Online (Sandbox Code Playgroud)

哪种方法占用更多内存?在第二种方法中,线程在被激活后结束了吗?或者它是否保留在内存中并启动新线程?(多线程)

mat*_*ata 6

Timer 为每个启动的计时器创建一个新的线程对象,因此在创建和垃圾收集这些对象时肯定需要更多的资源.

由于每个线程在它产生后立即退出另一个active_count保持不变,但是不断有新的线程被创建和销毁,这会导致开销.我会说第一种方法肯定更好.

尽管间隔非常小,但你不会真正看到太大的差异.


aba*_*ert 5

以下是如何自己测试的示例:

而第二种方法中,线程被激活后是否结束?或者它是否保留在内存中并启动一个新线程?(多线程)

import threading

def keepalive():
    print 'Alive.'
    threading.Timer(200, keepalive).start()
    print threading.active_count()

threading.Timer(200, keepalive).start()
Run Code Online (Sandbox Code Playgroud)

我还将 200 更改为 0.2,因此不会花费那么长时间。

线程数永远是 3。

然后我这样做了:

top -pid 24767
Run Code Online (Sandbox Code Playgroud)

#TH 列从未更改。

所以,这就是你的答案:我们没有足够的信息来知道 Python 是否为所有定时器维护一个单一的定时器线程,或者在定时器运行后立即结束并清理线程,但我们可以确定线程不会不要留下来堆积。(如果您确实想知道前者发生了什么,您可以,例如,打印线程 ID。)

另一种找出方法是查看源。正如文档所说,“Timer 是 Thread 的子类,因此也可以作为创建自定义线程的示例”。它是 的子类这一事实Thread已经告诉您,每个Timer都是Thread. 并且它“作为示例起作用”这一事实意味着它应该易于阅读。如果您单击从文档到源代码的链接,您会看到它是多么的简单。大部分工作是由 完成的Event,但这在同一个源文件中,而且几乎一样简单。实际上,它只是创建一个条件变量,等待它(因此它会阻塞直到超时,或者您通过调用 通知条件cancel),然后退出。

我之所以要回答一个子问题并解释我是如何做到的,而不是回答每个子问题,是因为我认为按照相同的步骤对您来说会更有用。

进一步思考,这可能不是首先由优化决定的问题:

如果您有一个简单的同步程序,需要在 200 秒内不执行任何操作,请对sleep. 或者,更简单的方法是完成工作然后退出,然后选择一个外部工具来安排您的脚本每 200 秒运行一次。

另一方面,如果你的程序本质上是异步的——特别是如果你已经有了线程、信号处理程序和/或事件循环——那么你就没有办法开始sleep工作。如果Timer效率太低,请转到 PyPI 或 ActiveState 并找到更好的计时器,让您可以使用单个实例和线程安排可重复的计时器(甚至多个计时器)。(或者,如果您使用的是信号,请使用signal.alarmor setitimer,如果您使用的是事件循环,请将计时器构建到您的主循环中。)

我想不出任何使用情况下的sleep,并Timer都希望能有力竞争者。