我有以下代码:

var things = await GetDataFromApi(cancellationToken);

var builder = new StringBuilder(JsonSerializer.Serialize(things));

await things
    .GroupBy(x => x.Category)
    .ToAsyncEnumerable()
    .SelectManyAwaitWithCancellation(async (category, ct) =>
    {
        var thingsWithColors = await _colorsApiClient.GetColorsFor(category.Select(thing => thing.Name).ToList(), ct);
        
        return category
            .Select(thing => ChooseBestColor(thingsWithColors))
            .ToAsyncEnumerable();
    })
    .ForEachAsync(thingAndColor =>
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId); // prints different IDs
        builder.Replace(thingAndColor.Thing, $"{thingAndColor.Color} {thingAndColor.Thing}");
    }, cancellationToken);

它用的是System.Linq.Async,我觉得很难理解. 在"classic "/同步LINQ中,只有当我对其调用ToList()ToArray()时,整个代码才会执行.在上面的例子中,没有这样的调用,但是lambda无论如何都会被执行.它怎麽工作?

我关注的另一个问题是多线程.我听过很多次,异步!=多线程.那么,Console.WriteLine(Thread.CurrentThread.ManagedThreadId);怎么可能打印不同的身份证呢?一些ID被多次打印,但输出中总共大约有5个线程ID.我的代码中没有一个显式创建任何线程.这一切都是在等待. StringBuilder不支持多线程,我想了解一下上面的实现是否有效.

请忽略我的代码的算法,这并不重要,这只是一个例子.重要的是System.Async.Linq的使用.

推荐答案

ForEachAsync将具有与ToList/To数组类似的效果,因为它强制对整个列表求值.

默认情况下,await之后的任何内容都在相同的execution context上继续,这意味着如果代码在UI线程上运行,它将继续在UI线程上运行.如果它在后台线程上运行,它将继续在后台线程上运行,但不一定是same线程.

但是,您的任何代码都不应运行in parallel.这并不一定意味着它是线程安全的,可能需要一些内存屏障来确保正确刷新数据,但我认为这些屏障是由框架代码本身发出的.

Csharp相关问答推荐

. NET Core DB vs JSON模型设计

`Task`只有在C#中等待时才会运行吗?

如何从HttpContext获取请求正文

实现List T,为什么LINQ之后它不会返回MyList?<>(无法强制转换WhereListIterator `1类型的对象)'

在一个模拟上设置一个方法,该模拟具有一个参数,该参数是一个numc函数表达式

有没有办法在WPF文本框中添加复制事件的处理程序?

如何测量在使用UTF8而不是C#中的UTF16编码字符串时内存使用量的增长

如何使用EF Core和.NET 8来upsert到具有多对多关系的表?

Linux Docker上的.NET6在某个时间抛出后,在加密操作期间发生System.Security.Cryptography.CryptographicException:错误

如何管理Azure认证客户端响应和证书 fingerprint

如何在CSharp中将json字符串转换为DataTable?

在字符串C#之前获取数字

为值对象编写自定义JsonConverter

在C#.NET项目中启动时,如何等待提升的PowerShell进程退出?

当try 测试具有协变返回类型的抽象属性时,类似功能引发System.ArgumentException

我应该为C#12中的主构造函数参数创建私有属性吗?

如何在C#中从MongoDB IPipelineStageDefinition中获取聚合命令的字段/选项?

使用DI实例化带有动态参数的服务?

读取测试项目中的应用程序设置

CsvHelper在第二次迭代时抛出System.ObjectDisposedException