Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步调用异步委托?_C#_Asynchronous_Async Await_Task Parallel Library - Fatal编程技术网

C# 异步调用异步委托?

C# 异步调用异步委托?,c#,asynchronous,async-await,task-parallel-library,C#,Asynchronous,Async Await,Task Parallel Library,下面是我想做的简单版本: private static int Inc(int input) { return input + 1; } private static async Task<int> IncAsync(int input) { await Task.Delay(200); return input + 1; } private static async Task<IEnumerable<TResult>> GetRe

下面是我想做的简单版本:

private static int Inc(int input)
{
    return input + 1;
}

private static async Task<int> IncAsync(int input)
{
    await Task.Delay(200);
    return input + 1;
}

private static async Task<IEnumerable<TResult>> GetResultsAsync<TInput, TResult>(Func<TInput, TResult> func, IEnumerable<TInput> values)
{
    var tasks = values.Select(value => Task.Run(() => func(value)))
                      .ToList();
    await Task.WhenAll(tasks);
    return tasks.Select(t => t.Result);
}

public async void TestAsyncStuff()
{
    var numbers = new[] { 1, 2, 3, 4 };
    var resultSync = await GetResultsAsync(Inc, numbers); // returns IEnumerable<int>
    Console.WriteLine(string.Join(",", resultSync.Select(n => $"{n}")));
   // The next line is the important one:
    var resultAsync = await GetResultsAsync(IncAsync, numbers); // returns IEnumerable<Task<int>>
}
但是我想收紧代码并执行
wait
inline。它应该是这样的:

var resultAsync = await GetResultsAsync(async n => await IncAsync(n), numbers);
但这也会返回一个
IEnumerable
!我可以这样做:

var resultAsync = await GetResultsAsync(n => IncAsync(n).GetAwaiter().GetResult(), numbers);
这就行了。。。但据我所见,不鼓励使用
Task.GetAwaiter().GetResult()
Task.Result


那么正确的方法是什么呢?

您应该创建两个
GetResultsAsync
的重载。应该接受返回
TResult
的“同步”委托。此方法将每个委托包装成一个任务,并异步运行它们:

private static async Task<IEnumerable<TResult>> GetResultsAsync<TInput, TResult>(
   Func<TInput, TResult> func, IEnumerable<TInput> values)
{
    var tasks = values.Select(value => Task.Run(() => func(value)));
    return await Task.WhenAll(tasks);
}

我得说,你关心的是文体:你想要读得更好的东西。对于您的第一个案例,请考虑:

var resultSync= numbers.AsParallel()/*.AsOrdered()*/.Select(Inc);
因为Plinq已经完成了您想要做的事情:它并行化了
IEnumerables
。对于第二种情况,在
任务
周围创建
任务
是没有意义的。相当于:

var resultAsync = numbers.AsParallel()./*AsOrdered().*/Select(n => IncAsync(n).Result);
但我更喜欢Sergey的
等待任务.WhenAll(numbers.Select(IncAsync))


也许我真正喜欢的是Linq风格的一对重载:

var numbers = Enumerable.Range(1,6);
var resultSync = await Enumerable.Range(1,6).SelectAsync(Inc);
var resultAsync = await Enumerable.Range(1,100).SelectAsync(IncAsync);

Console.WriteLine("sync" + string.Join(",", resultSync));
Console.WriteLine("async" + string.Join(",", resultAsync));


static class IEnumerableTasks
{
    public static Task<TResult[]> SelectAsync<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> func)
    {
        return Task.WhenAll( source.Select(async n => await Task.Run(()=> func(n))));
    }

    public static Task<TResult[]> SelectAsync<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, Task<TResult>> func)
    {
        return Task.WhenAll(source.Select(func));
    }
}
static int Inc(int input) 
{ 
    Task.Delay(1000).Wait();
    return input+1;
}

static async Task<int> IncAsync(int input)
{
    await Task.Delay(1000);
    return input + 1;
}
var编号=可枚举范围(1,6);
var resultSync=await Enumerable.Range(1,6)。选择Async(Inc);
var resultAsync=await Enumerable.Range(1100)。选择异步(IncAsync);
Console.WriteLine(“sync”+string.Join(“,”,resultSync));
Console.WriteLine(“async”+string.Join(“,”,resultAsync));
静态类IEnumerableTasks
{
公共静态任务SelectAsync(此IEnumerable源,Func Func)
{
return Task.WhenAll(source.Select(async n=>wait Task.Run(()=>func(n)));
}
公共静态任务SelectAsync(此IEnumerable源,Func Func)
{
返回Task.WhenAll(source.Select(func));
}
}
静态整数公司(整数输入)
{ 
Task.Delay(1000.Wait();
返回输入+1;
}
静态异步任务IncAsync(int输入)
{
等待任务。延迟(1000);
返回输入+1;
}

顺便说一句,如果您将
范围(1,6)
更改为
范围(1,40)
显示了异步的优势。在我的机器上,当异步版本停留在一秒钟左右时,同步的时间可能会急剧上升,甚至对于
范围(100000)

var resultAsync=wait GetResultsAsync(n=>IncAsync(n).Result,number)?不要使用
异步void
,它仅用于事件处理程序。您不能等待
异步void
方法也
等待任务;返回任务。选择(t=>t.Result)?为什么?若所有任务都有返回类型,
whalll
返回一个结果数组。通过清理代码,您应该能够编写
int[]results=wait Task.WhenAll(tasks)你到底想做什么?如果您最终调用了
Task.Run
,为什么不使用
Parallel.For
Task.Run
不会使任何东西异步,它在后台并行运行作业。For()
用于
操作,而不是
Func
s?我想说Plinq是用于
Funcs
这太棒了。最后,基于前面提到的性能考虑,我将您的答案与Sergey的答案结合起来,使用了
.aspallel()
。不幸的是,我只能给你们中的一个答案……:)
var resultSync = await Task.WhenAll(numbers.Select(x => Task.Run(() => Inc(x))));
var resultAsync = await Task.WhenAll(numbers.Select(IncAsync));
var resultSync= numbers.AsParallel()/*.AsOrdered()*/.Select(Inc);
var resultAsync = numbers.AsParallel()./*AsOrdered().*/Select(n => IncAsync(n).Result);
var numbers = Enumerable.Range(1,6);
var resultSync = await Enumerable.Range(1,6).SelectAsync(Inc);
var resultAsync = await Enumerable.Range(1,100).SelectAsync(IncAsync);

Console.WriteLine("sync" + string.Join(",", resultSync));
Console.WriteLine("async" + string.Join(",", resultAsync));


static class IEnumerableTasks
{
    public static Task<TResult[]> SelectAsync<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> func)
    {
        return Task.WhenAll( source.Select(async n => await Task.Run(()=> func(n))));
    }

    public static Task<TResult[]> SelectAsync<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, Task<TResult>> func)
    {
        return Task.WhenAll(source.Select(func));
    }
}
static int Inc(int input) 
{ 
    Task.Delay(1000).Wait();
    return input+1;
}

static async Task<int> IncAsync(int input)
{
    await Task.Delay(1000);
    return input + 1;
}