轮询正确的方法? [英] Polling the right way?

查看:399
本文介绍了轮询正确的方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一位软件/硬件工程师,在C和嵌入式技术方面拥有相当丰富的经验.目前,我正在忙于使用硬件进行数据采集的C#(.NET)编写一些应用程序.现在,以下内容对我来说很棘手:

I am a software/hardware engineer with quite some experience in C and embedded technologies. Currently i am busy with writing some applications in C# (.NET) that is using hardware for data acquisition. Now the following, for me burning, question:

例如:我有一台机器,该机器带有用于检测轴的最终位置的末端开关.现在,我正在使用USB数据采集模块读取数据.目前,我正在使用线程来连续读取端口状态.

For example: I have a machine that has an endswitch for detecting the final position of an axis. Now i am using a USB Data acquisition module to read the data. Currently I am using a Thread to continuously read the port-status.

此设备上没有中断功能.

There is no interrupt functionality on this device.

我的问题:这是正确的方法吗?我应该使用计时器,线程还是任务?我知道大多数人都讨厌投票,但是欢迎任何建议!

My question: Is this the right way? Should i use timers, threads or Tasks? I know polling is something that most of you guys "hate", but any suggestion is welcome!

推荐答案

IMO,这在很大程度上取决于您的实际环境,但是首先-在大多数情况下,您不应再使用线程. Tasks 越方便,越方便强大的解决方案.

IMO, this heavily depends on your exact environment, but first off - You should not use Threads anymore in most cases. Tasks are the more convenient and more powerful solution for that.

  • 低轮询频率:Tick事件中的计时器+轮询:
    计时器易于操作和停止.无需担心线程/任务在后台运行,但是处理发生在主线程中

  • Low polling frequency: Timer + polling in the Tick event:
    A timer is easy to handle and stop. No need to worry about threads/tasks running in the background, but the handling happens in the main thread

中轮询频率:Task + await Task.Delay(delay):
await Task.Delay(delay)不会阻塞线程池线程,但是由于上下文切换,最小延迟为〜15ms

Medium polling frequency: Task + await Task.Delay(delay):
await Task.Delay(delay) does not block a thread-pool thread, but because of the context switching the minimum delay is ~15ms

高轮询频率:Task + Thread.Sleep(delay)
可用延迟为1毫秒-实际上,我们这样做是为了轮询我们的USB测量设备

High polling frequency: Task + Thread.Sleep(delay)
usable at 1ms delays - we actually do this to poll our USB measurement device

这可以通过以下方式实现:

This could be implemented as follows:

int delay = 1;
var cancellationTokenSource = new CancellationTokenSource();
var token = cancellationTokenSource.Token;
var listener = Task.Factory.StartNew(() =>
{
    while (true)
    {
        // poll hardware

        Thread.Sleep(delay);
        if (token.IsCancellationRequested)
            break;
    }

    // cleanup, e.g. close connection
}, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

在大多数情况下,您只能使用Task.Run(() => DoWork(), token),但是没有提供TaskCreationOptions.LongRunning选项的重载,它告诉任务计划程序不要使用普通的线程池线程.
但是如您所见,Tasks更易于处理(并且await可用,但不适用于此处).特别是在此实现中,停止"只是从代码中的任何位置调用cancellationTokenSource.Cancel().

In most cases you can just use Task.Run(() => DoWork(), token), but there is no overload to supply the TaskCreationOptions.LongRunning option which tells the task-scheduler to not use a normal thread-pool thread.
But as you see Tasks are easier to handle (and awaitable, but does not apply here). Especially the "stopping" is just calling cancellationTokenSource.Cancel() in this implementation from anywhere in the code.

您甚至可以在多个操作中共享此令牌,并立即停止它们.此外,取消令牌后,尚未启动的任务也不会启动.

You can even share this token in multiple actions and stop them at once. Also, not yet started tasks are not started when the token is cancelled.

您还可以将另一个操作附加到一个任务上,以在一个任务之后运行:

You can also attach another action to a task to run after one task:

listener.ContinueWith(t => ShutDown(t));

然后在侦听器完成之后执行此操作,您可以执行清理操作(t.Exception如果未成功执行,则包含task操作的异常).

This is then executed after the listener completes and you can do cleanup (t.Exception contains the exception of the tasks action if it was not successful).

这篇关于轮询正确的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆