この質問は、r-devel メーリング リストでSimon Urbanek によって回答されました。今後の参考のために、彼の回答のコピーの下に:
この違いの原因は何ですか?
制限時間は R_ProcessEvents() でのみチェックできるため、実際には、R_CheckUserInterrupt() を呼び出す割り込み可能なコードによってのみトリガーできます。ここで、イベントのループ方法を決定するのは完全にフロントエンド次第です。たとえば、R の端末バージョンには、非同期でトリガーされる入力ハンドラー以外に心配する割り込みがないため、ポーリングを行う必要はありません。Sys.sleep() は入力ハンドラーでのみトリガーするため、入力ハンドラーとして外部イベント ソース フックがない場合、イベントを処理する理由がないため、Sys.sleep() は、制限時間。
時間制限がトリガーされるように、ターミナル R セッションで設定できるものはありますか?
OS X では、実際には非常に簡単ですquartz(); dev.off()
。その理由は、ウィンドウからのイベントを非同期的に処理するために、Quartz がイベント ループを強制する必要があるためです。これは、タイマーベースの入力ハンドラーをインストールすることによって行われます。このハンドラーは、Sys.sleep() が 100 ミリ秒ごとにウェイクアップするようにします (QuartzCocoa_SetLatency を使用して値を変更できます) ので、その解像度でタイムアウトします。
> testlimit <- function(){
+ setTimeLimit(elapsed=3, transient=TRUE);
+ Sys.sleep(10);
+ }
> system.time(testlimit());
Error in Sys.sleep(10) : reached elapsed time limit
Timing stopped at: 0 0.001 10.001
> quartz(); dev.off()
null device
1
> testlimit <- function(){
+ setTimeLimit(elapsed=3, transient=TRUE);
+ Sys.sleep(10);
+ }
> system.time(testlimit());
Error in Sys.sleep(10) : reached elapsed time limit
Timing stopped at: 0.002 0.003 3.019
Linux には組み込みのタイマーがないため、Sys.sleep() を横取りする入力ハンドラーを追加する必要があります。一定のタイマーが必要な場合は、Quartz (src/library/grDevices/src/qdCocoa.m の QuartzCocoa_SetupEventLoop を参照) または CarbonEL パッケージからコードを借りることができます。これは実際には、イベント ループを起動したいときに非同期に書き込む入力ハンドラーとして追加される単なるパイプです。私の頭の上では、この時点で R の組み込みソリューションを考えることができません (制限が設定されたときに R 自体がハンドラーをインストールする可能性があると主張することはできますが...)。
ただし、これは実際には Sys.sleep() の特殊なケースであることに注意してください。実際に R コードを実行すると、ProcessEvents が評価中に (または中断可能な C コードで) 自動的にトリガーされます。
乾杯、サイモン