【问题标题】:How to avoid a task to block the main thread?如何避免一个任务阻塞主线程?
【发布时间】:2017-03-24 21:33:09
【问题描述】:

假设你有以下代码:

Action action = () =>
{
  MethodThatReadSomeDataFromExternalHardware();
};

Task.Run(action);

MethodThatReadSomeDataFromExternalHardware() 方法连接到硬件设备并返回一些数据。

哪种设备与问题无关。

现在,如果该硬件已断开连接,MethodThatReadSomeDataFromExternalHardware() 方法会在尝试连接时卡住。

嗯……问题是当那个方法卡住的时候,主线程也卡住了,直到发生硬件超时。

有没有办法避免这种情况?当然,这只是一种原子方法,所以我不能在其中添加循环或其他东西以允许在主线程中进行消息处理。

我怀疑这是不可能的,但我想知道是否有一些 C# 指令或 Windows API 来启动并行任务,如果该子进程卡住,不会影响主线程。

注意 詹姆

【问题讨论】:

  • 在异步方法中运行它以将其从 UI 线程中释放出来。此外,如果您可以检测到硬件何时断开连接,那么您可以在任务中使用取消令牌来取消任务。取消令牌不会取消已开始的任务,但是您可以在任务正在执行的工作中定期检查该令牌是否已被取消,如果是则退出工作。
  • 是否没有 API 允许您与硬件进行异步通信?如果您可以将MethodThatReadSomeDataFromExternalHardware 中的那些同步调用更改为异步调用,那么您会处于一个更好的位置。
  • 你为什么不awaiting TaskTask.Run 返回?
  • Task.Run 已经在使用线程池,因此您的代码的问题出在调用线程中。如果没有硬件,你能提供卡住的代码吗?
  • 我不能……因为该方法只是硬件制造商提供的一种方法……该原子方法尝试打开与 TCP/IP 设备的连接,如果无法建立连接,则会卡住

标签: c# multithreading task multitasking


【解决方案1】:

不要使用任务

如果你只是想让方法完成而不关心结果会发生什么——或者——你可以在另一个线程中处理它;不要使用Tasks,因为它们比thread pool 重,并且需要.Net 4.5

使用线程池

它可能比TPL 有点旧,也没有那么花哨,但它符合要求。您使用ThreadPool 的方式与使用Task 的方式大致相同。而不是调用Run,而是调用QueueUserWorkItem

ThreadPool.QueueUserWorkItem(_ => {
   MethodThatReadSomeDataFromExternalHardwareAsync();
});

这样您既可以享受更轻的ThreadPool,又可以让您的代码更便携。

【讨论】:

  • 任务开销的任何基准?他们也在使用线程池,你知道的,那么你如何衡量呢? TPL 也需要 .Net 4.5。也许您将它与来自 C#5.0 和 .Net 4.6 的 async/await 混淆了?
  • @VMAtm 你错过了我说的,任务是 TPL,线程池不是。至于性能差异 - 任务使用线程周围的包装器并使用任务调度程序。除了使用线程池本身之外,所有这些。所以除非所有这些开销都为零,是的,有一个小的开销。
  • @ISun 这甚至没有回答这个问题。我们正在等待这些基准测试结果。
猜你喜欢
  • 2014-04-12
  • 2011-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-06
  • 2015-05-25
  • 2012-06-06
相关资源
最近更新 更多