【问题标题】:Penalties of a script constantly looping in the background脚本的惩罚在后台不断循环
【发布时间】:2009-04-23 14:08:25
【问题描述】:

我知道这个话题一直在discussedpast,但是我对资源使用有点偏执。

我正在考虑编写一个用于排队作业的守护程序,以将文件归档到我正在开发的 Web 应用程序的 zip 文件中。它的行为是这样的:

while True:
    while morejobs():
        zipfile()
    sleep(15seconds)

在后台不断循环的进程会消耗什么样的资源(假设没有要压缩的东西)?有什么我应该注意或小心的吗?

编辑:

看起来大多数答案都与睡眠时间有关。我一次盲目地将其设置为睡眠(在代码示例中)15 毫秒。我实际上打算将其设置为 15 秒,并且我已经“更新”了代码以反映这一点。

再次编辑:

脚本休眠的最低合理时间是多少? 5秒低吗?我不知道这个应用程序的负载是多少,也不知道新作业多久会添加到队列中。

【问题讨论】:

  • 其实你原来的代码是正确的。 time.sleep() 需要几秒钟(毫秒通过传递一个浮点参数来表示,例如 0.001)

标签: python resources performance queue


【解决方案1】:

睡眠不涉及开销。 Linux 操作系统使用一个非常简单的信号来唤醒一个睡眠进程。

您展示的是“忙于等待”的设计模式。

为了消除开销,您只想在有工作要做时才被唤醒。

这样做的方法。

  1. 等待读取。

  2. 等待选择函数调用。见http://docs.python.org/library/select.html

  3. 等待释放锁。见http://docs.python.org/library/posixfile.html

其中,等待读取可能是最简单的。从管道或套接字读取是您想要做的。

我猜你有一个“多作者单读者”的设计模式。在这种情况下,有两个候选解决方案。

  1. 每个套接字有多个请求。这是一个类似于 FTP 的解决方案,您可以编写一个简单的服务器来侦听一个套接字上的连接并为每个客户端打开一个专用连接。然后您使用 select 来确定哪个客户端正在发送文件。

  2. 每个套接字单个请求。这是类似 HTTP 的解决方案,您在某个套接字中接收请求,并且请求是大量数据。当请求全部完成后,套接字将关闭,以便另一个客户端可以获取它。

在这两种情况下,您不是在睡觉,而是在等待 I/O 完成。

【讨论】:

    【解决方案2】:

    为什么不使用 cron 作业每隔一分钟左右运行一次脚本呢?至少你不依赖于你自己的循环在后台连续运行。

    【讨论】:

    • 一个 cron 作业给了更多的 CPU 负载,因为循环休眠相同的持续时间,因为程序必须加载到内存中,并且每次迭代都会创建一个新进程。在循环中,它只运行一个循环,然后重新进入睡眠状态。
    • 我认为对于在我的机器上持续运行的自定义脚本来说,使用标准的尝试和真正简单的 cron 开销是值得的。我猜是他们自己的。
    【解决方案3】:

    如果文件到达需要 20 秒(这些数字是示例),而您需要 5 秒来处理它,那么您的进程在检测到之前平均再等待 7.5 秒会有什么危害文件在吗?

    休眠进程对 CPU 的影响应尽可能接近于零。

    所以不,我根本不会关心这个方面。

    您应该关心的一件事是如果进程失败,如何自动重新启动进程。我会每 5 分钟运行一次 cron 作业(您选择的实际频率)以杀死旧副本(礼貌地,并且仅在它正在运行时),然后启动一个新副本。这样,如果出现问题,最多只会有 5 分钟的停机时间。

    我礼貌地说,因为旧的可能正在处理文件,你不应该打断它,除非它是可恢复的。

    【讨论】:

      【解决方案4】:

      与其休眠 15 秒,不如设置一个回调,以便在新文件到达时重新启动您的工作。

      • 处理可用文件
      • 每 60 秒或您选择的任何间隔检查一次新文件
      • 当新文件到达时,处理它以及自上次间隔以来可能到达的任何其他文件

      【讨论】:

      【解决方案5】:

      作为替代方案,您可以降低进程的优先级。 (我只熟悉windows方法)

      在 Windows 上:

      def setpriority(pid=None,priority=1):
          """ Set The Priority of a Windows Process.  Priority is a value between 0-5 where
              2 is normal priority.  Default sets the priority of the current
              python process but can take any valid process ID. """
      
          import win32api,win32process,win32con
      
          priorityclasses = [win32process.IDLE_PRIORITY_CLASS,
                             win32process.BELOW_NORMAL_PRIORITY_CLASS,
                             win32process.NORMAL_PRIORITY_CLASS,
                             win32process.ABOVE_NORMAL_PRIORITY_CLASS,
                             win32process.HIGH_PRIORITY_CLASS,
                             win32process.REALTIME_PRIORITY_CLASS]
          if pid == None:
              pid = win32api.GetCurrentProcessId()
          handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid)
          win32process.SetPriorityClass(handle, priorityclasses[priority])
      

      来自: http://code.activestate.com/recipes/496767/

      【讨论】:

        【解决方案6】:

        这可能会影响您的 CPU,即使没有要处理的内容。

        编辑: 实际上sleep() 将参数作为秒数,而不是毫秒,所以我认为 CPU 不会成为问题。不过,也许您可​​以使用 cron 作业来安排这样的事情。

        【讨论】:

        • 这应该是可再分发的,并且能够以最少的麻烦进行设置。我想我已经增加了一点“复杂性”,而没有到处都有 cron 工作。
        【解决方案7】:

        除了重击你的 CPU 的成本之外,还有调用 morejobs() 的成本。您可以通过为 sleep() 使用更高的值来缓解,或者您可以使用某种邮箱接收请求然后触发 zipfile() 操作。

        对于某些操作来说,安排一个后台线程来临时检查某些东西是正常的。在这种情况下,最好为 sleep() 使用合理的值。

        【讨论】:

          【解决方案8】:

          “一千个有道理的意见值得一试”。

          试试吧。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-07-10
            • 1970-01-01
            • 2012-05-12
            • 2018-12-06
            • 1970-01-01
            • 2021-06-13
            相关资源
            最近更新 更多