【问题标题】:C# .NET choice of Multithreading approachC# .NET 选择多线程方法
【发布时间】:2016-12-02 15:43:53
【问题描述】:

我已经查看了多个关于 SO 的类似问题,但我仍然无法回答我自己的问题。

我有一个控制台应用程序(实际上是一个 Azure Webjob),它执行文件处理和数据库管理。一些大量数据从多个来源下载并在数据库中处理。

这是我的代码示例:

var dbLongIndpendentProcess = doProcesAsync();

var myfilesTasks  = files.Select(file => Task.Run(
                async () =>
{
// files processing 
}

await myfilesTasks.WhenAll();
await dbLongIndpendentProcess;
// continue with other stuff;

一切正常,并符合我的预期。在整个过程中还有其他任务在运行,但我想从上面的代码中可以清楚地看到这个想法。

我的问题:这是解决这个问题的一种公平方式,还是我会通过执行良好的旧“手动”多线程来获得更多性能(或意义?)?我选择这种方法的主要原因是它简单明了。

但是,async/await 的主要目的不是为了不阻塞主 (UI) 线程而进行异步操作。在这里,我没有任何 UI,也没有做任何事情。事件驱动。

谢谢,

【问题讨论】:

  • 您不需要立即await 调用,您可以触发一个任务,将其分配给一个变量,然后执行一些额外的工作并在稍后需要该值时等待该任务。例如,在厨房里,你会煮米饭,但你不会等锅烧开,而是先完成其他工作,然后再检查锅。就“手动”多线程而言,创建线程可能会很昂贵,尤其是如果您不知道自己在做什么,我个人认为这取决于您的偏好,尤其是工作的复杂性。
  • 值得补充的是,您应该正确实现取消模式,因为您明确地处理长任务。
  • 是的,长时间运行的任务应该有一个CancellationToken,这样您就可以优雅地清理和释放资源,而不是简单地撕掉一个可能导致意外行为的ThreadTask
  • @ColinM 请帮助我理解。 “你不需要立即等待调用,你可以触发一个任务,将它分配给一个变量,然后执行一些额外的工作,然后在需要值时等待任务。”这是一般性评论还是参考我的代码,在我看来,我正在这样做。还是我在这里遗漏了什么?
  • 一般来说作为一个指针,因为很多人倾向于引入 asyncawait 关键字,同时期望在真正执行操作时提高性能 异步。查看您的代码,您可以通过拆分操作并将其分配给 dbLongIndependentProcess 然后 await 稍后执行该任务来完成它。

标签: c# .net multithreading asynchronous async-await


【解决方案1】:

我不认为你使用这种方法是多线程的(除了单个 Task.Run),异步通常不会在单独的线程上运行东西,它只会防止事情阻塞。见:https://msdn.microsoft.com/en-gb/library/mt674882.aspx#Anchor_5

async 和 await 关键字不会导致额外的线程 创建的。异步方法不需要多线程,因为异步 方法不在自己的线程上运行。该方法在当前运行 同步上下文并仅在线程上使用时间 方法处于活动状态。您可以使用 Task.Run 将 CPU 密集型工作移动到 后台线程,但后台线程对进程没有帮助 那只是在等待结果可用。

将任务用于您想要多线程的事情会更好,然后您可以更好地利用机器内核和资源。您可能想查看基于任务的解决方案,例如流水线(可能在这种情况下工作)等...:https://msdn.microsoft.com/en-gb/library/ff963548.aspx 或其他替代方案。

【讨论】:

  • 如果我理解正确,在我的代码中,dbLongIndpendentProcess 仍将在主线程上运行,但不会阻塞流,因为那里实际上没有发生任何事情,但是我的 myfilesTasks 集合将并行运行。 (嗯,我知道他们会...:))
  • @agfc DB 操作没有在主线程上发生。它根本不使用任何线程来完成它的工作。这项工作不需要你的 CPU 时间来取得进展。
  • @Servy 显然 DB 操作没有,但问题是:“是否在同一个线程上创建了名为 dbLongIndpendentProcess 的 c# 任务”?似乎它确实在同一个线程上,并且由于异步它没有阻止调用方法的执行。我说的对吗?
  • @agfc 如果它是一个同步的 CPU 绑定操作,那么它会阻塞直到它完成,并且您的代码不会并行工作。当您想在线程池线程中异步运行同步 CPU 绑定操作时,您可以使用 Task.Run 创建一个表示该工作由线程池完成的任务。
  • 我对此不是 100%,但我认为它会像从线程内部异步一样运行它,我不确定它的副作用.. 我猜是在那里你可以在函数内部使用 async await ,但实际上你并不需要它,因为你在一个新线程中,只有你所在的函数会被阻塞。我会删除它,以防它做一些有意义的事情,比如绕过任务的异常处理等......
猜你喜欢
  • 1970-01-01
  • 2013-05-28
  • 2016-12-19
  • 1970-01-01
  • 2011-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多