【问题标题】:Task.Run Serial CommunicationsTask.Run 串行通信
【发布时间】:2013-12-19 14:34:44
【问题描述】:

我真的很喜欢使用 MVVM 和 async/await,所以自然而然地,我将一个项目组合在一起进行了一个新的开发 (MVVM),它通过串行方式与设备通信以工作并且 UI 具有响应性。我的驱动程序类是同步调用,它通过串行方式与设备通信,并且可能需要时间(尽管通常不会),具体取决于返回的数据量、是否获得适当的返回或驱动程序是否应该继续等待几秒钟看看是否有适当的回报,等等。

无论如何,我最终做的是将通信包装在 await Task.Run(()=>{});包装。这样,从我的 UI 角度来看,当用户单击按钮时,它会神奇地被抛出到线程池中,并且我的 UI 在处理任务时保持响应。

下面的实现不正确吗?由于我通过串行通信,我的工作在技术上不是 I/O 绑定工作而不是 CPU 绑定工作(据我所读,Task.Run 应该仅用于 CPU 绑定工作)?通过执行以下操作在我的视图模型中调用以下方法:

var returnVal = await _objName.InitAsync();

然后是 Task.Run 调用....

    public async Task<bool> InitAsync()
    {
        bool returnVal = false;

        await Task.Run(() =>
        {
            System.Threading.Thread.Sleep(COMMAND_DELAY_MILLISECONDS);
            returnVal = _obj.InitiateProvision();
        });

        return returnVal;
    }

bool 返回值只是说明命令是否成功。代码工作得很好,因为我已经测试了大约一个月,没有任何问题,但我不确定它是否是最好的......有没有“更好”的方法来做到这一点,同时仍然能够维护异步操作?任何指导表示赞赏!

【问题讨论】:

  • 打电话给InitiateProvision之前睡觉有什么意义? InitiateProvision 也很慢吗?
  • 只是为了在发送命令之前添加一个短暂的延迟,我有大约 3 个命令我像这样按顺序调用,所以我添加了这个以在两次调用之间留出一些时间。我不确定这是否是最好的......使用串行端口对我来说相当新。
  • 您可以从 Task.Run 返回 _obj.InitiateProvision 的返回值,从而避免捕获 returnVal 局部变量,从而避免创建类型和实例化。

标签: c# mvvm serial-port task-parallel-library async-await


【解决方案1】:

如果您使用Task.Run 只是为了在执行命令之前有延迟,只需使用delay 并且不要占用线程池。

public async Task<bool> InitAsync()
{
    bool returnVal = false;

    await Task.Delay(COMMAND_DELAY_MILLISECONDS).ConfigureAwait(false);
    returnVal = _obj.InitiateProvision();

    return returnVal;
}

您说您有 3 个命令,如果适合您的设计,您可以连续执行所有三个命令,一个函数中可以有多个 await

public async Task<bool> InitAsync()
{
    bool returnVal = false;

    await Task.Delay(COMMAND_DELAY_MILLISECONDS).ConfigureAwait(false);
    returnVal = _obj.InitiateProvision();

    if(returnVal == true)
    {
        await Task.Delay(COMMAND_DELAY_MILLISECONDS).ConfigureAwait(false);
        returnVal = _obj.CommandTwo();
    }

    if(returnVal == true)
    {
        await Task.Delay(COMMAND_DELAY_MILLISECONDS).ConfigureAwait(false);
        returnVal = _obj.CommandThree();
    }

    return returnVal;
}

.ConfigureAwait(false) 使得函数在await 之后继续工作时不需要返回 UI 线程,并且由于不需要在 UI 线程中等待轮到它可以使程序更快.

【讨论】:

  • 我刚刚看到您更新的评论 - InitiateProvision 调用速度很慢,并且会占用 UI。延迟只是用来在调用之间提供一些缓冲 - 我肯定会添加 Task.Delay,但是将 InitiateProvision 调用包装在 Task.Run 中是否仍然可以。
  • 好的,太棒了!那么“await Task.Delay”用于延迟,并在“await Task.Run”中包装 InitiateProvision 和类似的缓慢调用?
  • 我仍然会尽量避免在你的函数中使用Task.Run。相反,您仍然可以使用async 并执行await Task.Delay,但不要在此函数中使用Task.Run,而是执行await Task.Run(() =&gt; InitAsync());,这样您就有了 caller 包装函数在 Task.Run 中。
  • 您这样做的原因是,如果您曾经从非 UI 线程调用 InitAsync,则不需要 Task.Run,因此您可以灵活地选择绑定线程池线程或不取决于你的需要。
猜你喜欢
  • 1970-01-01
  • 2013-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多