web-dev-qa-db-ja.com

DispatchSourceTimer、Timer、asyncAfterの違いは?

DispatchSourceTimerTimerasyncAfterのスケジューリングの主な違いを理解するのに苦労していますX秒ごとに実行する必要があるタスクですが、タイマーの違いを理解することは役立ちます)(または、Swiftリストされたタイマー以外に?).

Timerは、開始された現在のキューにアクティブな実行ループが必要です。 DispatchSourceTimerはそれを必要としません。 Timerは、CPUがアイドル状態にならないようにします。これはDispatchSourceTimer/asyncAfterにも適用されますか?

どのような状況でTimerDispatchSourceTimer/asyncAfterより優先されますか?そしてもちろん、それらすべての違いは?

アプリケーションの専用キューで15秒ごとに作業をスケジュールしたい。これは、メインスレッドではないキューにいるため、DispatchSourceTimerを使用する必要があることを意味します(または、キューに実行ループを追加してTimerを使用します)。しかし、そもそもTimerを使用するだけのメリットはありません。多分私がDispatchSourceTimerより効率的なプライベートキューでX秒ごとにそのスケジュール作業を使用できる別の操作があるかもしれませんが、私はより良い解決策に出くわしませんでした。

DispatchSourceTimerTimerよりも効率的ですか?または、asyncAfterを使用して自己呼び出しメソッドを実行する必要がありますか?

これはタイマーを作成するコードです。

asyncAfter

DispatchQueue.global().asyncAfter(deadline: .now() + .seconds(2)) {
    // Code
}

タイマー

Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { (_) in
    // Code
}

DispatchSourceTimer

let timer = DispatchSource.makeTimerSource()

timer.schedule(deadline: .now() + .seconds(1))

timer.setEventHandler {
    // Code
}

timer.activate()

すべてのタイマーの短所と長所は何ですか?どちらを上に使用すればよいですか?どのタイマーが最も効率的ですか?私は次のことを思いつきました:

タイマー

長所:

  • 無効にできる
  • 参照は必要ありません
  • スケジュールされている間は停止できます。

短所:

  • CPUがアイドル状態にならないようにする
  • 実行ループのあるキューで実行する必要があります(それ以外の場合は何も起こらず、アサーショントリガーもありません...)

DispatchSourceTimer

長所:

  • キャンセル可能
  • 実行ループは不要

短所:

  • 強力な参照が必要です。それ以外の場合、即座に割り当てが解除されます

asyncAfter

長所:-実行ループは不要

短所:-キャンセルできない(私は思う)

さらにタイマーはありますか?なぜこんなにたくさんのタイマーがあるのですか?さまざまなタイマーすべてに実際の違いがあると期待していましたが、見つかりませんでした。

あなたが読むことができるように、ここにたくさんの質問があります。主な質問は次のとおりです:利用可能なタイマーと、どのような場合にどのタイマーを使用する必要がありますか?

25
J. Doe

タイマーは、Swift NSTimerのブリッジです。これは、Grand Central Dispatch(GCD)よりもずっと前にNeXTSTEPに戻ります。DispatchSourceTimerのようなものは、10.6まで(フォームでは) dispatch_source_set_timer)およびdispatchAfter(dispatch_afterの形式)。

NSTimerは実行ループに基づいています。これは、GCDまで並行性が実行される主要な方法でした。これは協調型同時実行システムであり、シングルコアのシングルスレッドで実行するように主に設計されています(ただし、マルチスレッド環境に拡張できます)。

実行ループは、Cocoaでは依然として非常に重要ですが、並行性を管理するための主要な方法ではなく、優先される方法でさえありません。 10.6以降、GCDはますます推奨されるアプローチになっています(ただし、ブロックベースのNSTimer APIを10.12のタイムフレームに追加することは歓迎すべき近代化でした)。

15秒というスケールでは、効率の違いはほとんど関係ありません。とはいえ、私はあなたのコメントを理解できません。「タイマーはCPUがアイドル状態に入らないようにします」私はそれが本当だとは思わない。 NSTimerの起動を待機しているとき、CPUは確実にアイドル状態になります。

NSTimerを実行するためだけに実行ループを設定することはしません。メインの実行ループでスケジュールし、次にDispatchQueue.async他のキューで実際の作業を行う。

原則として、私はニーズを満たす最高レベルのツールを使用します。これらは、Appleは、時間をかけて最適化する可能性が高いものであり、変更を最小限に抑えます。たとえば、NSTimerの起動日は、エネルギー効率を改善するために自動的に調整されます。DispatchSourceTimerを使用すると、同じ利点を得るためにleeway設定を超えていますが、設定するかどうかはあなた次第です(デフォルトはゼロであり、これはエネルギーへの影響が最も大きくなります)。もちろん、その逆も当てはまります。DispatchSourceTimerは最小ですレベルとあなたに最もコントロールを与えるので、それがあなたが必要なものであるなら、それが使うべきものです。

あなたの例では、おそらく個人的にはタイマーを使用し、ブロックの一部としてプライベートキューにディスパッチするだけです。しかし、DispatchSourceTimerは完全に適切です。

asyncAfterは常にワンショットなので、実際には別のものです。ワンショットが必要な場合はこれで十分ですが、繰り返したい場合は状況が変わります。ブロックでasyncAfterを呼び出して繰り返す場合、15秒間隔ではなく、最後に終了した後15秒になります。前者は少し遅れてドリフトする傾向があります。設計上の問題は次のとおりです。何らかの理由でタスクの完了に5秒かかった場合、次の火災イベントをその終了から15秒後に発生させますか、それとも各火災イベントの間に一定の15秒を確保しますか?そこでの選択により、どのツールが正しいかが決まります。

少し注意しておきますが、NSTimerイベントは常にスケジュールより少し遅れます。余裕のある設定のGCDイベントは、少し早い場合と少し遅い場合があります。実際問題として、「予定通り」であることなどはありません(それは長さがゼロの期間です。あなたはそれにぶつからないでしょう)。したがって、問題は常に、NSTimerのように約束遅くなるのか、それともGCDのように余裕を持って早くなるのかということです。

37
Rob Napier