5

2つのクラスがあります。1つ(A)はいくつかのデータを収集し、もう1つ(B)はデータをTCP/IPクライアントに送信します。このプロセスは非同期で、リフレッシュレートはほぼゼロから数秒です。このアプリケーションにはGUIがないため、多くの組み込みの「onChange」リスナーを使用できないことに注意してください。

通常の状態では、AがBで「send」メソッドを呼び出してデータを渡すようにコードを記述するだけです。ここでは問題ありません。

ここで、Aがデータを収集する速度が重要(リアルタイム)であり、AがBが送信プロセスを完了するのを待つことができないと仮定します(BはUDPではなくTCPを使用することに注意してください)。私がこれを実装した方法は

  • AはデータをBのフィールドに配置します
  • Bには、データが新しいか現在かをチェックする連続ループがあります。新品の場合は発送します。

送信中にデータが数回更新されても、Aの速度が低下しない限り、問題はありません。送信ごとに新しいスレッドを生成しても、原則としてAの速度は低下しませんが、混乱が生じる可能性があります。 。

Bが同期モードで動作していることがわかります(ただし、Aは動作していません)。また、Thread.sleep()呼び出しを使用したwhileループで実装されています。私の質問は次のとおりです。

  1. whileループの代わりにタイマータスクを使用する必要がありますか?ほとんどの人がThread.sleep()呼び出しを嫌うことは知っていますが、最終的に私が興味を持っているのはCPUを低く保つことだけです。

  2. 同期アプローチよりもエレガントな方法はありませんか?場合によっては、Aのデータ更新は約1秒であり、イベントに作用するリスナーがあればいいのですが。このような場合、25msのスリープ時間はサイクルの無駄になります。他の場合、それは非常に速く、私は全く眠りたくないです。

*例:Aが画面からスクリーンショットを送信し、Bがそれらをクライアントに送信していると想像してください。最後の1つだけが重要で、Bはできるだけ速く進みます*

何かアイデアや提案はありますか?できるだけシンプルでCPUを低くしてください

どうもありがとう!

4

4 に答える 4

2

キューがいっぱいになったときにサイズがブロックされないように、 LinkedBlockingQueuebetweenAを設定します。では、データを収集するメソッドがデータをキューに送信します。で、キューにアイテムがある限り、それは新しく、送信する必要があります。BAAB

マージして単一の更新として送信することBにより、メッセージに対する複数の編集を利用したい場合は、を使用して行います。AObserver

  1. A更新を続けるメッセージはObservableです。
  2. Bこのメッセージのオブザーバーです。
  3. Aメッセージを更新するたびに、Bが何らかのアクションを実行するように指示されます。
  4. B更新をクライアントにすぐに送信することを選択できます
  5. Bまた、タイマーを使用して一定時間待機し、タイマーが起動した後にのみクライアントに更新を送信することを選択できます。更新を送信するコードはTimerTaskになります。
  6. BAメッセージを変更するまで、タイマーを再設定しません。
于 2012-09-16T14:21:24.530 に答える
2

私はそれをこのようにします:

Aは、適切な方法でデータを収集し、送信する「次のメッセージ」を投稿します。保留中のメッセージがすでにある場合は、新しいメッセージで前のメッセージを置き換え/更新します。

Bは、保留中のメッセージをチェックします。メッセージが利用可能な場合は、それを取得してクライアントに送信します。ただし、保留中のメッセージがない場合、Bはメッセージが使用可能になるのを待ちます。

Object lock = new Object();
Object pending = null;

public void post(Object message) {
    synchronized (lock) {
        pending = message;
        lock.notifyAll();
    }
}

public Object getNextMessage() {
    Object message;
    synchronized (lock) {
        while (pending == null) {
            try {
                lock.wait();
            } catch (InterruptedException e) {
                // Ignore
            }
        }
        message = pending;
        pending = null;
    }
    return message;
}

代わりにキューを使用して行うことができます

BlockingDeque<Object> queue = new LinkedBlockingDeque<Object>(1);

public void postMessage(Object message) {
    // If previous message is still pending we replace it.
    queue.clear();
    queue.offer(message);
}

public Object getNextMessage() {
    while (true) {
        try {
            return queue.take();
        } catch (InterruptedException e) {
            // Ignore interrupts
        }
    }
}

もちろん、どちらの例でも、while(true)の代わりにシグナルを使用して、正常にシャットダウンできるようにすることをお勧めします。

于 2012-09-16T14:35:46.343 に答える
2

Exchangerを使用できます

Bは情報を送信し、交換機を使用して交換します(Aとその罰金を待つ場合があります)
交換が行われると、彼は情報を送信します。

Aはタイムアウト0で交換機を使用します。つまり、Bがまだ待機していない場合は、この交換をスキップします。交換が待機している場合、Aは仕事を続行し、Bは情報を送信できるようになります。

Bがビジーの間に来る情報は無視されます(タイムアウト0のAでの交換は、Bがビジーの場合、例外をスローします。必ずキャッチしてください)

于 2012-09-16T14:47:06.907 に答える
1

最も洗練された方法は、メッセージキューを使用することです。Aデータが利用可能になるとすぐにキューに書き込みます。Bはキューにサブスクライブし、新しいデータが入るたびに通知されます。メッセージキューがすべてを処理します。

ただし、より明確にする必要がありBます。メッセージごとに通知する必要がありますか?アップデートが失われた場合はどうなりますか?

于 2012-09-16T14:20:58.597 に答える