当前位置: 首页 > 知识库问答 >
问题:

异步LINQ-不是懒惰吗?多线程?

百里光熙
2023-03-14

我有以下代码:

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);

它使用<code>System.Linq。异步,我发现很难理解。在“经典”/“同步LINQ”中,只有在调用<code>ToList()

我担心的另一个问题是多线程。我听过很多次异步!=多线程。那么,< code >控制台怎么可能。WriteLine(线程。CurrentThread . ManagedThreadId);打印各种id?有些id被打印了多次,但总的来说,输出中大约有5个线程id。我的代码都没有显式创建任何线程。这都是异步等待。< code>StringBuilder不支持多线程,我想知道上面的实现是否有效。

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

共有2个答案

羊舌光赫
2023-03-14

<代码>系统。Async.Linq,以及整个dotnet/reactive存储库,目前是一个半废弃的项目。GitHub上的问题堆积如山,几乎一年都没有人正式回答。除了每个方法的源代码中的XML文档之外,没有发布任何文档。如果不研究源代码,你就不能真正使用这个库,这通常很容易做到,因为代码很短,可读性强,而且老实说不会做太多。该库提供的功能与< code >系统中的功能相似。Linq,主要区别在于输入是< code>IAsyncEnumerable

除了像< code>Merge(以及它的一个重载)这样的少数运算符之外,< code >系统。Async.Linq没有引入并发性。一次调用一个异步操作,然后在调用下一个操作之前等待它们。< code > selectmanyawaitwithcassignment 运算符不在例外之列。为每个元素顺序调用< code >选择器,并生成< code>IAsyncEnumerable

< code > foreach sync 运算符只是执行标准的< code>await foreach循环的替代品,在C#语言不支持< code>await foreach时(在C# 8之前)就包含在库中了。我建议不要使用这个操作符,因为它与新的< code >类似。foreach sync API可能会造成混乱。以下是写在< code > foreach sync 运算符源代码中的内容:

// REVIEW: Once we have C# 8.0 language support, we may want to do away with these
//         methods. An open question is how to provide support for cancellation,
//         which could be offered through WithCancellation on the source. If we still
//         want to keep these methods, they may be a candidate for
//         System.Interactive.Async if we consider them to be non-standard
//         (i.e. IEnumerable<T> doesn't have a ForEach extension method either).
楚望
2023-03-14

ForEachAsync将具有与ToList/ToArray类似的效果,因为它强制评估整个列表。

默认情况下,等待之后的任何内容都在同一执行上下文中继续,这意味着如果代码在 UI 线程上运行,它将继续在 UI 线程上运行。如果它在后台线程上运行,它将继续在后台线程上运行,但不一定是同一个线程。

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

 类似资料:
  • 问题内容: 我在Linux上编写了一个C程序,该程序可以分配内存,并在一个循环中运行它,而TOP没有显示任何内存消耗。 然后我对该内存做了一些操作,而TOP确实显示了内存消耗。 当我分配内存时,我真的是“获取内存”,还是有一个“惰性”内存管理,仅当使用时才给我内存? (还有一个选项,当我使用它时,TOP只知道内存消耗,因此我不确定。) 谢谢 问题答案: 在Linux上,malloc使用sbrk()

  • 问题内容: 考虑以下代码: 当第一个URL够用时会被要求输入第二个URL吗? 我尝试了一个较小的示例,它看起来像预期的那样工作。即一个一个地处理数据,但是可以依靠这种行为吗?如果没有,在帮助之前打电话吗? 输出: 更新 :如果对实施很重要,请使用官方Oracle JDK8 答案 :根据下面的评论和答案,flatmap部分是惰性的。即完全读取第一个流,并且仅在需要时才读取下一个。渴望读取一个流,但是

  • 我有一个数据表的问题-懒加载。我认为问题是在IdiomasBean.java(TableBean.java),如果我把: 我得到了正确的数据表,但是<代码>按排序、筛选和不起作用。 我得到:java。lang.NullPointerException这里是堆栈跟踪: 下面是代码的其余部分: 指数xhtml diomasBean.java 懒散的数据模型。JAVA IdiomasBo.java 习语

  • 我试着把我的头绕到相对较新的img属性“加载”上。 我知道,如果img具有load=“lazy”属性,那么它会告诉支持该属性的浏览器,在接近视口时可以加载该属性。 那么为什么不总是设置loading=“lazy”?那些立即出现在屏幕上的图像无论如何都会被渲染,因为它们已经在视口中了。因此,在这种情况下,基本上忽略了load=“lazy”。 在这个演示https://mathiasbynens.be

  • 问题内容: 我想创建自己的集合,该集合具有python list的所有属性,并且还知道如何将自身保存到数据库中或从数据库中加载。我也想使负载隐式和惰性,因为在列表创建时它不会发生,而是等到第一次使用时才发生。 有没有一种单一的方法,我可以覆盖上加载任何列表属性(如第一次使用清单,,而不必重写他们… …等)? 问题答案: 不,没有。

  • 问题内容: https://nodejs.org/api/fs.html#fs_fs_createreadstream_path_options。我也有一个一般性的问题。 我是否可以假设,除非文档中另有说明,否则提及的任何函数都是异步的? 问题答案: createreadstream是异步的吗? 是的,没有。这个问题实际上是一个语义问题,而不是任何问题,因为它在同步外观界面下隐藏了一个异步操作。