Jam*_*ery 100 c# async-await
使用ForEach时是否可以使用Async?以下是我正在尝试的代码:
using (DataContext db = new DataLayer.DataContext())
{
db.Groups.ToList().ForEach(i => async {
await GetAdminsFromGroup(i.Gid);
});
}
Run Code Online (Sandbox Code Playgroud)
我收到错误:
当前上下文中不存在名称"Async"
包含using语句的方法设置为async.
Ste*_*ary 156
List<T>.ForEachasync由于同样的原因,LINQ-to-objects 也没有特别好用.
在这种情况下,我建议将每个元素投射到异步操作中,然后您可以(异步)等待它们全部完成.
using (DataContext db = new DataLayer.DataContext())
{
var tasks = db.Groups.ToList().Select(i => GetAdminsFromGroupAsync(i.Gid));
var results = await Task.WhenAll(tasks);
}
Run Code Online (Sandbox Code Playgroud)
这种方法比给予async代表的好处ForEach是:
async void不能被抓住catch; 这种方法将在该await Task.WhenAll行传播异常,允许自然异常处理.await Task.WhenAll.如果使用async void,则无法轻易判断操作何时完成.GetAdminsFromGroupAsync听起来这是一个产生结果的操作(管理员),如果这样的操作可以返回结果而不是将值设置为副作用,则此类代码更自然.JD *_*toy 50
这个小扩展方法应该为您提供异常安全的异步迭代:
public static async Task ForEachAsync<T>(this List<T> list, Func<T, Task> func)
{
foreach (var value in list)
{
await func(value);
}
}
Run Code Online (Sandbox Code Playgroud)
由于我们正在将lambda的返回类型更改void为Task,因此异常将正确传播.这将允许你在实践中写这样的东西:
await db.Groups.ToList().ForEachAsync(async i => {
await GetAdminsFromGroup(i.Gid);
});
Run Code Online (Sandbox Code Playgroud)
Rub*_*uck 22
简单的答案是使用foreach关键字而不是 的ForEach()方法List()。
using (DataContext db = new DataLayer.DataContext())
{
foreach(var i in db.Groups)
{
await GetAdminsFromGroup(i.Gid);
}
}
Run Code Online (Sandbox Code Playgroud)
And*_*ski 19
从 开始C# 8.0,您可以异步创建和使用流。
private async void button1_Click(object sender, EventArgs e)
{
IAsyncEnumerable<int> enumerable = GenerateSequence();
await foreach (var i in enumerable)
{
Debug.WriteLine(i);
}
}
public static async IAsyncEnumerable<int> GenerateSequence()
{
for (int i = 0; i < 20; i++)
{
await Task.Delay(100);
yield return i;
}
}
Run Code Online (Sandbox Code Playgroud)
小智 13
这不是一个老问题,但.Net 6引入了Parallel.ForeachAsync:
var collectionToIterate = db.Groups.ToList();
await Parallel.ForEachAsync(collectionToIterate, async (i, token) =>
{
await GetAdminsFromGroup(i);
});
Run Code Online (Sandbox Code Playgroud)
ForeachAsync 还接受 ParallelOptions 对象,但通常您不想弄乱MaxDegreeOfParallelism 属性:
ParallelOptions parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = 4 };
var collectionToIterate = db.Groups.ToList();
await Parallel.ForEachAsync(collectionToIterate, parallelOptions , async (i, token) =>
{
await GetAdminsFromGroup(i);
});
Run Code Online (Sandbox Code Playgroud)
默认情况下,For 和 ForEach 将利用底层调度程序提供的线程数,因此更改默认值的 MaxDegreeOfParallelism 仅限制将使用的并发任务数。
一般来说,你不需要修改这个设置......
小智 8
以下是具有顺序处理的上述异步foreach变体的实际工作版本:
public static async Task ForEachAsync<T>(this List<T> enumerable, Action<T> action)
{
foreach (var item in enumerable)
await Task.Run(() => { action(item); }).ConfigureAwait(false);
}
Run Code Online (Sandbox Code Playgroud)
这是实施:
public async void SequentialAsync()
{
var list = new List<Action>();
Action action1 = () => {
//do stuff 1
};
Action action2 = () => {
//do stuff 2
};
list.Add(action1);
list.Add(action2);
await list.ForEachAsync();
}
Run Code Online (Sandbox Code Playgroud)
关键区别是什么?.ConfigureAwait(false);它保持主线程的上下文,同时对每个任务进行异步顺序处理.
Jam*_*ery -2
问题是async关键字需要出现在 lambda 之前,而不是主体之前:
db.Groups.ToList().ForEach(async (i) => {
await GetAdminsFromGroup(i.Gid);
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
90151 次 |
| 最近记录: |