如何在异步和同步之间切换。NET/C#
How to switch between async & sync in .NET/C#
如何在 C# 中切换 async/sync 多个任务处理?
出于 testing/profiling 目的,我希望能够在任务的并行和同步处理之间切换。
最初我有一组内联初始化的任务。虽然这对于并行来说很好,但我发现我的同步代码不起作用,因为每个方法都会在数组初始化时被激活。
我决定改用 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。
您的方法可行,但我会避免为此使用 Lazy。
C# 中已经有一个惰性语言构造,它是 yield return,它会产生更清晰的代码:
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; }
}
这样,该方法在生产和测试中仍然异步运行。
如何在 C# 中切换 async/sync 多个任务处理?
出于 testing/profiling 目的,我希望能够在任务的并行和同步处理之间切换。
最初我有一组内联初始化的任务。虽然这对于并行来说很好,但我发现我的同步代码不起作用,因为每个方法都会在数组初始化时被激活。
我决定改用 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。
您的方法可行,但我会避免为此使用 Lazy。
C# 中已经有一个惰性语言构造,它是 yield return,它会产生更清晰的代码:
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; }
}
这样,该方法在生产和测试中仍然异步运行。