可以比每10秒更频繁地启动运行的程序吗?


8

我有一些这样的服务,我希望在文件修改后立即运行。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN
http://www.apple.com/DTDs/PropertyList-1.0.dtd>
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>test</string>
    <key>ProgramArguments</key>
    <array>     
        <string>say</string>
        <string>a</string>
    </array>
    <key>WatchPaths</key>
    <array>
        <string>/Users/username/Desktop/</string>
    </array>
</dict>
</plist>

即使ThrottleInterval设置为1或0,它们最多也只能每10秒运行一次。

9/9/12 4:57:05.457 PM com.apple.launchd.peruser.501[138]: (test) Throttling respawn: Will start in 7 seconds
9/9/12 4:57:09.541 PM com.apple.launchd.peruser.501[138]: (test) Throttling respawn: Will start in 3 seconds

man launchd.plist 只说默认情况下程序运行不超过每10秒一次,但没有提到ThrottleInterval不能设置为低于该值。

ThrottleInterval <integer>
This key lets one override the default throttling policy imposed on jobs by launchd.
The value is in seconds, and by default, jobs will not be spawned more than once
every 10 seconds.  The principle behind this is that jobs should linger around just
in case they are needed again in the near future. This not only reduces the latency
of responses, but it encourages developers to amortize the cost of program invoca-
tion.

您可以使程序或脚本运行10秒钟,并每秒监视更改:

#!/bin/bash

start=$(date +%s)
prev=

until (( $(date +%s) >= $start + 10 )); do
    new=$(stat -f %m ~/Desktop/)
    [[ $prev != $new ]] && say a
    prev=$new
    sleep 1
done

还是与Ruby中的相同:

#!/usr/bin/env ruby

start = Time.now
prev = nil

until Time.now >= start + 10
  current = File.mtime("#{ENV['HOME']}/Desktop/")
  `say a` if current != prev
  prev = current
  sleep 1
end

但是,有什么方法可以绕过或减少时间限制吗?它也适用于文件夹操作。

Answers:


9

无法绕过或减少时间限制。

Apple有关创建启动的作业的文档规定如下:

重要说明:如果守护程序在启动后关闭得太快,则启动可能会认为它已崩溃。继续这种行为的守护程序可能会被挂起,并且在以后的请求到达时不会再次启动。为避免这种情况,请在启动后至少10秒钟内不要关闭电源。

您的程序或脚本需要保持运行至少10秒钟。考虑实现一个循环,以检查最近十秒钟的文件修改日期,休眠十秒钟并重复执行。

另外,您可以使用kqueue或FSEvents API 监视特定文件。这个StackOverflow问题可能会有所帮助,Mac OS X中的文件级文件系统更改通知


2

您可以让脚本循环运行以检查修改后的文件,而不是在完成后退出。检查修改后的文件后,让它休眠几秒钟。如果找到修改后的文件,请继续执行脚本。如果没有,请再次入睡。

然后每隔X分钟启动一次脚本,以防先前的运行终止。对脚本的开头进行编码,以检查另一个实例是否已在运行,如果已运行,请退出自身。


如果前一个实例仍在运行,则launchd似乎不会启动另一个实例。
Lri 2012年

launchd将不会启动同一作业通知单的多个实例。
格雷厄姆·米尔恩

1

如果您需要比每10秒更频繁地启动一个脚本,那么在“分叉”方面可能会很昂贵(请阅读:分配内存,启动新进程等)。

因此,在这种情况下,最好编写自己的“ 守护程序 ”(程序,在后台运行)

我建议您使用一种“功能更强大”的语言作为BASH(我最喜欢的语言是“ perl”,但ruby也可以),因为一个好的守护进程可以处理超时,警报等,这在纯bash中很难实现。(当然,守护程序也可以运行bash脚本-如果需要的话)。基础知识是:

  • 脚本无休止地运行并等待某些事件。该事件可以是一些网络输入,也可以是简单的计时器或类似的东西。当事件到达时(例如,等待状态结束),脚本将执行您想要的操作,并且循环重复。

在perl世界中已经存在可以将脚本调整为“守护进程”的模块,例如Proc :: Daemon。我对红宝石没有经验,但是本文可以为您提供帮助。

您可以通过在系统启动时启动“启动”来启动守护进程,也可以在登录时从automator应用程序启动,也可以从终端手动启动。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.