有使用异步API的必要吗?

huangapple go评论102阅读模式
英文:

Is there any point in using async api

问题

I have data in memory (json strings):

List<string> data = new List<string>();
using (StreamReader sr = new StreamReader("file.txt"))
{
   while (sr.Peek() >= 0)
   {
      data.Add(sr.ReadLine());
   }
}

我有存储在内存中的数据(JSON字符串):

List<string> data = new List<string>();
using (StreamReader sr = new StreamReader("file.txt"))
{
   while (sr.Peek() >= 0)
   {
      data.Add(sr.ReadLine());
   }
}

and I want to filter these objects using System.Linq.Async:

var filteredData = data.WhereAwait(async x =>
    await filters.ToAsyncEnumerable().AllAwaitAsync(async filter =>
        (await JsonSerializer.DeserializeAsync<RootDto>(new MemoryStream(Encoding.UTF8.GetBytes(x))))
        .Child.Id == filter));

我想使用System.Linq.Async来筛选这些对象:

var filteredData = data.WhereAwait(async x =>
    await filters.ToAsyncEnumerable().AllAwaitAsync(async filter =>
        (await JsonSerializer.DeserializeAsync<RootDto>(new MemoryStream(Encoding.UTF8.GetBytes(x))))
        .Child.Id == filter));

I know this example is stupid, but this is just a general example of whether or not to use an async api in places where it links to a synchronous one. In this example I have List<string> data which is not async by nature. I understand that it makes more sense in a case when data is obtained from an object also asynchronously.
Is it better than the one above?

var filters = new[] {"U45TC0Y7KLLD", "ELXE5X1IXHZV", "KHI3NXKEN1PE", "A7R5LDD4O0NK", "1TIICSXMH7FJ"};
var filteredData = data.Where(filters.All(filter =>
                JsonSerializer.DeserializeAsync<RootDto>(new MemoryStream(Encoding.UTF8.GetBytes(x))).GetAwaiter()
                    .GetResult().Child.Id == filter));

我知道这个示例很愚蠢,但这只是一个一般性的示例,用来说明是否应该在与同步API链接的地方使用异步API。在这个示例中,我有一个不是自然异步的 List<string> data。我理解在数据也是异步获取的情况下更有意义。
这个示例是否比上面的示例更好?

var filters = new[] {"U45TC0Y7KLLD", "ELXE5X1IXHZV", "KHI3NXKEN1PE", "A7R5LDD4O0NK", "1TIICSXMH7FJ"};
var filteredData = data.Where(filters.All(filter =>
                JsonSerializer.DeserializeAsync<RootDto>(new MemoryStream(Encoding.UTF8.GetBytes(x))).GetAwaiter()
                    .GetResult().Child.Id == filter));
英文:

I have data in memory (json strings):

List&lt;string&gt; data = new List&lt;string&gt;();
using (StreamReader sr = new StreamReader(&quot;file.txt&quot;))
{
   while (sr.Peek() &gt;= 0)
   {
      data.Add(sr.ReadLine());
   }
}

and I want to filter these objects using System.Linq.Async:

var filteredData = data.WhereAwait(async x =&gt;
    await filters.ToAsyncEnumerable().AllAwaitAsync(async filter =&gt;
        (await JsonSerializer.DeserializeAsync&lt;RootDto&gt;(new MemoryStream(Encoding.UTF8.GetBytes(x))))
        .Child.Id == filter));

I know this example is stupid, but this is just a general example of whether or not to use an async api in places where it links to a synchronous one. In this example I have List&lt;string&gt; data which is not async by nature. I understand that it makes more sense in a case when data is obtained from an object also asynchronously.
Is it better than the one above?

var filters = new[] {&quot;U45TC0Y7KLLD&quot;, &quot;ELXE5X1IXHZV&quot;, &quot;KHI3NXKEN1PE&quot;, &quot;A7R5LDD4O0NK&quot;, &quot;1TIICSXMH7FJ&quot;};
var filteredData = data.Where(filters.All(filter =&gt;
                JsonSerializer.DeserializeAsync&lt;RootDto&gt;(new MemoryStream(Encoding.UTF8.GetBytes(x))).GetAwaiter()
                    .GetResult().Child.Id == filter));

I want to get explanation

答案1

得分: 0

我知道这个例子很愚蠢。

问题在于愚蠢的例子会让讨论特定问题的解决方案变得困难,因为对于不同变体的问题,可能有多种解决方案。而且你似乎完全不理解异步(GetAwaiter().GetResult()实在太糟糕了,以至于有一个专门的名字叫做异步覆盖同步反模式)。

至于愚蠢的例子,答案是否定的。通过将你所做的部分标记为“async”(请注意,实际上它并不是异步的,正如我在上面提到的,你只是喜欢这个关键字的外观,所以才添加了它)你不会获得任何好处。

然而,在愚蠢的例子中,有两个理论上可以使用async的地方:

  • 实际读取文件的部分。任何类型的I/O都是async的典型应用场景,可以确保你的进程的线程不会闲着,而是在其他系统组件(DMA传输芯片和操作系统调度程序)执行实际工作时能够继续工作。

  • 如果你消除了那个可怕的异步覆盖同步的代码,而是创建了并行反序列化代码的个别任务,然后等待它们。可以考虑使用Task.WhenAll。根据你要反序列化的项数以及它们的复杂性,这实际上可能会提供吞吐量的好处。

英文:

> I know this example is stupid

The problem is that stupid examples make talking about a specific problem's solution difficult when there are multiple solutions for different variations of said problem. Also it doesn't help that you don't seem to understand async at all (GetAwaiter().GetResult() is so incredibly bad that there's a name for it, the async-over-sync anti-pattern).

As far as the stupid example goes though, the answer is no. You gain nothing by making the portion you did "async" (note that it's not actually async, as I mentioned above, you just like how the keyword looks so you added it).

There are two theoretical places in the stupid example where async would be of use however:

  • the part where you actually read the file. I/O of any kind is exactly what async is made for, making it so your process' threads aren't just sitting around picking their nose as other system components (the DMA transfer chips and the OS scheduler) do the actual work.

  • If you got rid of that terrible async-over-sync code and instead created individual tasks that deserialize the code in parallel, then awaited that. Think Task.WhenAll. Depending on how many items you're deserializing and how complex they are, that could actually provide a throughput benefit.

huangapple
  • 本文由 发表于 2023年7月31日 22:33:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/76804633.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定