在Select LINQ方法中使用Task.Run() [英] use Task.Run() inside of Select LINQ method

查看:182
本文介绍了在Select LINQ方法中使用Task.Run()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有以下代码(仅出于学习目的):

Suppose I have the following code (just for learninig purposes):

static async Task Main(string[] args)
{
    var results = new ConcurrentDictionary<string, int>();

    var tasks = Enumerable.Range(0, 100).Select(async index =>
    {
        var res = await DoAsyncJob(index);
        results.TryAdd(index.ToString(), res);
    });

    await Task.WhenAll(tasks);

    Console.WriteLine($"Items in dictionary {results.Count}");
}

static async Task<int> DoAsyncJob(int i)
{
    // simulate some I/O bound operation
    await Task.Delay(100);

    return i * 10;
}

我想知道如果我做到以下几点会有什么区别:

I want to know what will be the difference if I make it as follows:

var tasks = Enumerable.Range(0, 100)
    .Select(index => Task.Run(async () =>
    {
        var res = await DoAsyncJob(index);
        results.TryAdd(index.ToString(), res);
    }));

在两种情况下我都得到相同的结果.但是代码执行是否类似?

I get the same results in both cases. But does code executes similarly?

推荐答案

Task.Run可以在线程池线程中执行CPU绑定的同步操作.因为您正在运行的操作已经是异步的,所以使用Task.Run意味着您正在调度要在线程池线程中运行的工作,而该工作仅仅是启动的异步操作,然后几乎立即完成,并且在不阻塞该线程池线程的情况下完成了它必须执行的所有异步工作.因此,通过使用Task.Run,您正在等待调度线程池中的工作,但实际上并没有任何有意义的工作.您最好只在当前线程中启动异步操作.

Task.Run is there to execute CPU bound, synchronous, operations in a thread pool thread. As it is the operation you're running is already asynchronous, so using Task.Run means you're scheduling work to run in a thread pool thread, and that work is merely starting an asynchronous operation, which then completes almost immediately, and goes off to do whatever asynchronous work it has to do without blocking that thread pool thread. So by using Task.Run you're waiting to schedule work in the thread pool, but then not actually don't any meaningful work. You're better off just starting the asynchronous operation in the current thread.

唯一的例外是DoAsyncJob的实现不正确,并且由于某种原因实际上不是异步的,这与它的名称和签名相反,并且实际上在返回之前做了很多同步工作.但是,如果这样做,则应该修复该错误方法,而不要使用Task.Run来调用它.

The only exception would be if DoAsyncJob were implemented improperly and for some reason wasn't actually asynchronous, contrary to its name and signature, and actually did a lot of synchronous work before returning. But if it is doing that, you should just fix that buggy method, rather than using Task.Run to call it.

另一方面,没有理由没有ConcurrentDictionary在这里收集结果. Task.WhenAll返回您已执行的所有任务的结果的集合.只是使用它.现在,您甚至都不需要包装任何异步方法并以任何特殊方式处理结果的方法,从而进一步简化了代码:

On a side note, there's no reason to have a ConcurrentDictionary to collect the results here. Task.WhenAll returns a collection of the results of all of the tasks you've executed. Just use that. Now you don't even need a method to wrap your asynchronous method and process the result in any special way, simplifying the code further:

var tasks = Enumerable.Range(0, 100).Select(DoAsyncJob);

var results = await Task.WhenAll(tasks);

Console.WriteLine($"Items in results {results.Count}");

这篇关于在Select LINQ方法中使用Task.Run()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆