2017-06-26 9 views
-2

データ転送の目的で、複数のイーサネット対応ハードウェアデバイス(最大100デバイス)に接続する1つのアプリケーション(C#と.net 4.5)を設計しました要求応答メカニズムを使用します。より効率的なthreading.timerまたはタスク並列ライブラリ.net 4.5の時代

各ハードウェアデバイスには固有のIPアドレスとポートが設定されています。私のアプリケーションはtcpclientクラスを使用して接続し、このデバイスと通信します。

今私の要件は、同時にすべてのデバイスを接続することができるようになりますように

  1. は、アプリケーションのマルチスレッド作り、です。
  2. これらのすべてのデバイスで発生する通信は反復的です。つまり、特定の間隔ごとに、24時間365日にすべてのデバイスにデータ転送の目的で接続する必要があります。
  3. 私はもう1つの追加要件がありますが、関数(コールバック関数)が実行を終了すると間隔を設定する必要があります。私は睡眠、遅延または同等の機能を使用することはできませんので、いくつかのデバイスが応答を遅らせるため。この場合、最後の反復が完了していない場合でも、新しい反復が開始される可能性があります。
  4. すなわち

私は、データ転送が起こる必要があり、それだけで後は、次の実行のための間隔を設定する必要があるデバイスに接続する場合。(おそらくコールバック関数自体に)

これを達成するために私が作るために考えていますthreading.timerを使用してください。コールバック関数自体でスレッド間隔を設定できます。私はこれをテストしており、当初は動作していたようです。私は、このコードを本番環境で動作させるためにさらに最適化できると信じています。

さらにGoogleをやって、タスク並列ライブラリがより効率的だと思っていました.net 4.5で作業して以来、私は古典的なthreading.timerクラスではなく、これを使うべきです。

しかし、TPLはthreading.timerとまったく同じではないので、私は自分の必要条件に完全に適合するように作業する必要があります。

私は、TPLをthreading.timerではなくカスタマイズして使用すると、本当にパフォーマンスが向上するのでしょうか、threading.timerだけを続けるべきですか?

+4

"アプリケーションをマルチスレッド化すると、同時にすべてのデバイスを接続できるようになります*"は誤解であり、間違ったパスにつながります。接続ごとにスレッドではなく、async IOを使用します。 – spender

+0

@spender私はそれを得た。私は確かではありませんが、接続ごとにスレッドを使用しても、接続が制限されているためパフォーマンスが低下することはありません。 –

+0

スレッドはありません。 IOはOSレベルでは非同期です。ブロッキングがシミュレートされます。 async/awaitを使用すると、スレッドを使用せずにネイティブの非同期機能を使用できます。 –

答えて

0

私は、このスレッドとTPLでMicrosoftのリアクティブフレームワーク(NuGet "System.Reactive")を使用することをお勧めします。

スタートし、各デバイスのスケジュールを変更するために使用することができますTimeSpan値の配列を定義することによって:ここで私はやるだろう何だ、私は2000ミリ秒のデフォルトを始めました

int devices = 3; 

TimeSpan[] timerTimeSpans = 
    Enumerable 
     .Range(0, devices) 
     .Select(x => TimeSpan.FromMilliseconds(2000)) 
     .ToArray(); 

そしてデバイスから読み取るための方法を定義する:

public Task<DeviceResult> DeviceFetchAsync(int device_number, Action<TimeSpan> reschedule) 
{ 
    if (device_number == 1) 
    { 
     reschedule(TimeSpan.FromMilliseconds(10000)); 
    } 

    return Task.Factory.StartNew(() => new DeviceResult() 
    { 
     DeviceNumber = device_number 
    }); 
} 

public class DeviceResult 
{ 
    public int DeviceNumber; 
} 

それは、この特定のデバイスのスケジューリングを変更するAction<TimeSpan> rescheduleを含みます。

IObservable<DeviceResult> query = 
    Observable 
     .Range(0, devices) 
     .Select(n => 
      Observable 
       .Generate(0, x => true, x => x + 1, x => x, x => timerTimeSpans[n]) 
       .SelectMany(x => 
        Observable 
         .FromAsync(() => DeviceFetchAsync(n, ts => timerTimeSpans[n] = ts)))) 
     .Merge(); 

そして全体をオフに設定し、最終的には、サブスクリプション:タイマーのすべてを設定し、デバイスから読み取ったRxクエリのための今すぐ

IDisposable subscription = 
    query 
     .Subscribe(r => Console.WriteLine(r.DeviceNumber)); 

したい場合すべてを停止するには、subscription.Dispose();を実行してください。

これだけです。それがすべてのコードです。私はこれをテストし、それは正常に動作します。

関連する問題