这是.net 4.5

时间:2017-06-26 11:39:26

标签: c# multithreading timer task-parallel-library

我设计了一个应用程序(C#with .net 4.5),它使用请求响应机制连接到多个支持以太网的硬件设备(最多100个设备)以进行数据传输。

每个硬件设备都配置了唯一的IP地址和端口,我的应用程序使用tcpclient类连接并与此设备通信。

现在我的要求是,

  1. 使应用程序具有多线程,以便能够同时连接所有设备。 (每个连接的线程数)
  2. 所有这些设备发生的通信都是重复的,即在每个特定的时间间隔之后,它应该连接到所有设备,以便在24X7的基础上进行数据传输。
  3. 我还有一个额外的要求是,一旦函数(回调函数)完成执行,应该配置间隔。因为某些时间设备延迟了响应所以我无法使用睡眠,延迟或等效功能。在这种情况下,即使最后一次迭代没有完成,也可以开始新的迭代,我想要阻止它。
  4. 即。如果我连接到设备数据传输应该发生,并且只有在它之后它应该设置下一次执行的间隔。(最可能在回调函数本身)

    为了实现这一点,我想使用threading.timer,为此我可以在回调函数本身设置线程间隔。我正在测试这个并且似乎最初工作,我相信我可以进一步优化此代码以在生产环境中工作。

    但是进一步的Google我开始相信任务并行库更有效率,因为我正在研究.net 4.5我应该使用这个而不是经典的threading.timer类。

    但由于TPL与threading没有完全相同。我必须努力使其完全符合我的要求。

    所以我的问题是,如果我使用TPL进行一些自定义而不是threading.timer,我真的会获得任何性能提升,或者我应该继续使用threading.timer。

1 个答案:

答案 0 :(得分:0)

我建议在线程和TPL上使用Microsoft的Reactive Framework(NuGet“System.Reactive”)。这就是我要做的事情:

首先定义一个TimeSpan值数组,可用于更改每个设备的计划:

int devices = 3;

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

我的默认值为2000毫秒。

然后定义一个从设备读取的方法:

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以更改此特定设备的计划。

现在,对于设置所有定时器和从设备读取的Rx查询:

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();

最后订阅整个事情:

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

如果你想停止一切,只需subscription.Dispose();

就是这样。这就是所有的代码。我已经测试了这个并且工作正常。