如何处理同步的方法/任务异步使用/等待 [英] How to deal with synchronous method/task using async/await

查看:223
本文介绍了如何处理同步的方法/任务异步使用/等待的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解如何使用.NET 4.5异步/等待关键字任务,在它的核心是同步的。即一些复杂的数学计算。我已经使用了的Thread.Sleep来模拟在下面的示例中的行动。我的问题是那里你可以做出这样一个异步方法这种方法的行为方式?如果不这样做,你只需要做什么,我在ThisWillRunAsyncTest方法做了,做类似的东西Task.Factory.StartNew上同步方法。是否有这样做的更清洁的方式?

 使用的System.Threading;
使用System.Collections.Generic;
使用System.Threading.Tasks;使用NUnit.Framework;[的TestFixture]
公共类AsyncAwaitTest
{
    [测试]
    //这个测​​试将需要1秒运行,因为它运行异步
    //是否有更好的方式开始了同步任务,并将它并行运行。
    公共异步无效ThisWillRunAsyncTest()
    {
        VAR任务=新的List<任务>();
        的for(int i = 0;我小于5;我++)
        {
            tasks.Add(Task.Factory.StartNew(()=> this.RunTask()));
        }        等待Task.WhenAll(任务);
    }    [测试]
    //这个测​​试将需要大约5秒运行,因为它运行同步。
    //如果运行任务在它有一个的await,这这将同步运行。
    公共异步无效ThisWillRunSyncTest()
    {
        VAR任务=新的List<任务>();
        的for(int i = 0;我小于5;我++)
        {
            tasks.Add(this.RunTask());
        }        等待Task.WhenAll(任务);
    }    //这就是我想要并行运行一些同步任务的一个例子。
    //有什么我可以在这个方法中,使async关键字的工作吗?即从调用时,这将异步运行ThisWillRunSyncTest
    公共异步任务RunTask()
    {
        Thread.sleep代码(1000);
    }
}


解决方案

作为一般规则,如果你的平行的工作要做,你应该使用平行或并行LINQ。

有一些时候很方便治疗CPU密集型的工作,仿佛它是异步的(即在后台线程上运行它)。这是 Task.Run 是(避免使用 StartNew ,因为我的describe~~V在我的博客)。

同步方法应该有同步的方法签名:

 公共无效RunTask()
{
  Thread.sleep代码(1000);
}

他们应该只被包裹在 Task.Run 如果调用code需要它(也就是说,它是一个UI组件的一部分,如视图模型)

  VAR任务=新的List<任务>();
的for(int i = 0;我小于5;我++)
{
  tasks.Add(Task.Run(()=> this.RunTask()));
}
等待Task.WhenAll(任务);

这里的原则是, Task.Run 应在调用中使用,不落实;我去到更多的细节在我的博客

请注意,如果您有任何真正的复杂性,您应该使用并行或并行LINQ,而不是 Task.Run 任务。 Task.Run 是罚款小东西,但它不具备所有的智慧并行类型做。所以,如果这是一个库的一部分(不一定在UI线程中运行),那么我推荐使用并行

 的Parallel.For(0,5,_ => this.RunTask());

作为最后一个侧面说明,异步单元测试方法应异步任务,而不是异步无效。 NUnit的V3已经删除了支持异步无效单元测试方法。

I'm trying to understand how to use the .net 4.5 async/await keywords with a Task that at it's core is synchronous. I.e. some sort of complex math calculation. I've used a Thread.Sleep to simulate that action in the example below. My question is there a way you can make such a method act like an async method? If not do you just need to do what I did in the ThisWillRunAsyncTest method and do something like Task.Factory.StartNew on that sync method. Is there a cleaner way of doing this?

using System.Threading;
using System.Collections.Generic;
using System.Threading.Tasks;

using NUnit.Framework;

[TestFixture]
public class AsyncAwaitTest
{
    [Test]
    //This test will take 1 second to run because it runs asynchronously
    //Is there a better way to start up a synchronous task and have it run in parallel.
    public async void ThisWillRunAsyncTest()
    {
        var tasks = new List<Task>();
        for (int i = 0; i < 5; i++)
        {
            tasks.Add(Task.Factory.StartNew(() => this.RunTask()));
        }

        await Task.WhenAll(tasks);
    }

    [Test]
    //This test will take 5 seconds to run because it runs synchronously.
    //If the Run Task had an await in it, this this would run synchronously.  
    public async void ThisWillRunSyncTest()
    {
        var tasks = new List<Task>();
        for (int i = 0; i < 5; i++)
        {
            tasks.Add(this.RunTask());
        }

        await Task.WhenAll(tasks);
    }

    //This is just an example of some synchronous task that I want to run in parallel.
    //Is there something I can do in this method that makes the async keyword work?  I.e. this would run asynchronously when called from ThisWillRunSyncTest
    public async Task RunTask()
    {
        Thread.Sleep(1000);
    }
}

解决方案

As a general rule, if you have parallel work to do, you should be using Parallel or parallel LINQ.

There are times when it's convenient to treat CPU-bound work as though it were asynchronous (i.e., running it on a background thread). This is what Task.Run is for (avoid using StartNew, as I describe on my blog).

Synchronous methods should have synchronous method signatures:

public void RunTask()
{
  Thread.Sleep(1000);
}

They should only be wrapped in Task.Run if the calling code requires it (i.e., it is part of a UI component such as a view model):

var tasks = new List<Task>();
for (int i = 0; i < 5; i++)
{
  tasks.Add(Task.Run(() => this.RunTask()));
}
await Task.WhenAll(tasks);

The principle here is that Task.Run should be used in the invocation, not the implementation; I go into more details on my blog.

Note that if you have any real complexity, you should be using Parallel or parallel LINQ instead of a collection of Task.Run tasks. Task.Run is fine for small stuff but it doesn't have all the smarts the parallel types do. So, if this is part of a library (and not necessarily running on a UI thread), then I'd recommend using Parallel:

Parallel.For(0, 5, _ => this.RunTask());

As a final side note, asynchronous unit test methods should be async Task, not async void. NUnit v3 has already removed support for async void unit test methods.

这篇关于如何处理同步的方法/任务异步使用/等待的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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