如何在async和amp;之间切换在.NET / C#中同步

时间:2015-09-15 13:40:30

标签: c# .net task-parallel-library

如何在C#中切换多个任务的异步/同步处理?

我希望能够在任务的并行和同步处理之间切换以进行测试/分析。

最初我有一个内联初始化的任务数组。虽然这对并行来说很好,但我发现我的同步代码不起作用,因为每个方法都会在数组初始化时激活。

我决定尝试Lazy。这段代码是否正确?如果没有,这是如何最好地实现的?

  var runTasks = new Lazy<Task<ProcessWithResult>>[]
            {
                new Lazy<Task<ProcessWithResult>>(() => GetHeaderRecord()),
                new Lazy<Task<ProcessWithResult>>(() => GetChildType1Entities()),
                new Lazy<Task<ProcessWithResult>>(() => GetChildType2Entities()),
                new Lazy<Task<ProcessWithResult>>(() => GetChildType3Entities()),                     
            };

            if (Settings.Default.AsyncProcessing)
            {
                Task.WaitAll(runTasks.Select(x => x.Value).ToArray());
            }
            else
            {
                // do these in sequence
                runTasks.ToList().ForEach(t => t.Value.Wait());
            }

            // carryon...

每个GetX()方法签名都是这样的:

public async Task<ProcessWithResult> GetChildType1Entities()

在数据库或文件i / o上至少进行一次异步操作。

1 个答案:

答案 0 :(得分:1)

你的方法可行,但我会避免使用Lazy。

C#中已经存在一个惰性语言构造,它的收益率会返回,并且会产生更清晰的代码:

public static class Runner
{
    public static async Task<IEnumerable<ProcessWithResult>> RunAll(this IEnumerable<Task<ProcessWithResult>> tasks, bool runSequentially)
    {
        if (!runSequentially) return await Task.WhenAll(tasks);
        var results = new List<ProcessWithResult>();
        foreach (var task in tasks)
            results.Add(await task);
        return results;
    }
}

public class Tests
{
    [Test]
    public void RunInParallel()
    {
        var results = GetAllTasks().RunAll(false).Result;
        CollectionAssert.AreEqual(new[] { 2, 1 }, results.OrderBy(r => r.WhenFinished).Select(r => r.Id));
    }

    [Test]
    public void RunInSequentially()
    {
        var results = GetAllTasks().RunAll(true).Result;
        CollectionAssert.AreEqual(new[] { 1, 2 }, results.OrderBy(r => r.WhenFinished).Select(r => r.Id));
    }

    IEnumerable<Task<ProcessWithResult>> GetAllTasks()
    {
        yield return RunTask(1, 1000);
        yield return RunTask(2, 100);
    }

    async Task<ProcessWithResult> RunTask(int id, int wait)
    {
        await Task.Delay(wait);
        return new ProcessWithResult {Id = id, WhenFinished = DateTime.Now};
    }
}

public class ProcessWithResult
{
    public int Id { get; set; }
    public DateTime WhenFinished { get; set; }
}

这种方法仍然在生产和测试中同步运行。