Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.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#_.net_Asp.net Mvc_Async Await - Fatal编程技术网

C# 一路异步问题

C# 一路异步问题,c#,.net,asp.net-mvc,async-await,C#,.net,Asp.net Mvc,Async Await,我有一个异步asp.net控制器。此控制器调用异步方法。在我的应用程序中,实际执行异步IO工作的方法是深入的。控制器和链中最后一个方法之间的一系列方法都用async修饰符标记。下面是我如何设置代码的示例: public async Task<ActionResult> Index(int[] ids) { List<int> listOfDataPoints = dataPointService(ids); List<Task> dpTaskL

我有一个异步asp.net控制器。此控制器调用异步方法。在我的应用程序中,实际执行异步IO工作的方法是深入的。控制器和链中最后一个方法之间的一系列方法都用async修饰符标记。下面是我如何设置代码的示例:

public async Task<ActionResult> Index(int[] ids)
{
    List<int> listOfDataPoints = dataPointService(ids);
    List<Task> dpTaskList = new List<Task>();
    foreach (var x in listOfDataPoints)
    {
        dpTaskList.Add(C_Async(x));
    }

    await Task.WhenAll(dpTaskList);
    return View();
}


private async Task C_Async(int id)
{
    //this method executes very fast
    var idTemp = paddID(id);
    await D_Async(idTemp);
}

private async Task D_Async(string id)
{
    //this method executes very fast
    await E_Async(id);
}

private async Task E_Async(string url)
{
    //this method performs the actual async IO
    result = await new WebClient().DownloadStringTaskAsync(new Uri(url))
    saveContent(result);
}
公共异步任务索引(int[]id)
{
List listOfDataPoints=dataPointService(ids);
List dpTaskList=新列表();
foreach(listOfDataPoints中的变量x)
{
添加(C_Async(x));
}
等待任务。WhenAll(dpTaskList);
返回视图();
}
专用异步任务C_async(int-id)
{
//此方法执行速度非常快
变量idTemp=paddID(id);
等待D_异步(idTemp);
}
专用异步任务D_async(字符串id)
{
//此方法执行速度非常快
等待E_异步(id);
}
专用异步任务E_async(字符串url)
{
//此方法执行实际的异步IO
结果=等待新的WebClient()。下载StringTaskAsync(新Uri(url))
保存内容(结果);
}
正如您所看到的,控制器异步调用C_Async(x),然后有一个异步方法链指向E_Async。控制器和E_Async之间有一些方法,它们都有Async修饰符。由于存在使用异步修改器但不执行任何异步IO工作的方法,是否存在性能损失

注意:这是实际代码的简化版本。控制器和E_异步方法之间有更多的异步方法。

是。这是一个惩罚(虽然不是很大的惩罚),如果你不需要异步
就不要这样做。这种模式通常被称为“return await”,在这种模式中,您几乎总是可以同时删除
async
await
。只需返回表示异步操作的现有任务:

private Task C_Async(int id)
{
    // This method executes very fast
    var idTemp = paddID(id);
    return D_Async(idTemp);
}

private Task D_Async(string id)
{
    // This method executes very fast
    return E_Async(id);
}

在这种特定情况下,
Index
将只
等待
E_Async
返回的任务。这意味着在所有
I/O
完成后,下一行代码将直接是
returnview()
C_Async
D_Async
已在同步调用中运行并完成。

必须注意线程消息泵以及Async的实际功能。下面的示例调用了一个async方法,该方法调用了另外两个async方法,这两个方法启动两个任务来执行实际工作,等待2秒和3秒

13.00 6520 .ctor Calling async method
13.00 6520 RunSomethingAsync Before
13.00 6520 GetSlowString Before
13.00 5628 OtherTask Sleeping for 2s
15.00 5628 OtherTask Sleeping done
15.00 6520 GetVerySlow Inside
15.00 2176 GetVerySlow Sleeping 3s
18.00 2176 GetVerySlow Sleeping Done
18.00 6520 RunSomethingAsync After GetSlowOtherTaskResultGetVerySlowReturn
正如您所看到的,调用是序列化的,这可能不是您在测试性能时所希望的。也许这两个不同的等待调用互不依赖,可以作为任务直接启动

在启动异步操作的UI或ASP.NET线程上调用GetSlowStringBefore之前的所有方法(如果有消息泵)。只有带有操作结果的最后一个调用被封送回发起线程

性能损失在ContextSwitch区域的某个地方,以唤醒已经存在的线程。这应该是微秒级。最昂贵的工作是创建托管对象和垃圾收集器清理临时对象。如果在紧循环中调用此函数,则会受到GC的约束,因为可以创建的线程数是有上限的。在这种情况下,TPL将把您的任务缓冲在需要内存分配的队列中,然后从线程池中排出带有n个工作线程的队列

在我的Core I7上,每次调用的开销为2微秒(注释掉Debug.Print行),在WPF应用程序中,500万次调用的内存消耗为6,5GB,每个异步操作链的内存开销为130KB。如果您追求高可伸缩性,则需要关注GC。在我们必须使用CLR之前,我们目前拥有

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Print("Calling async method");
        RunSomethingAsync();
    }

    private async void RunSomethingAsync()
    {
        Print("Before");
        string msg = await GetSlowString();
        Print("After " + msg);
        cLabel.Content = msg;
    }

    void Print(string message, [CallerMemberName] string method = "")
    {
        Debug.Print("{0:N2} {1} {2} {3}", DateTime.Now.Second, AppDomain.GetCurrentThreadId(), method, message);
    }

    private async Task<string> GetSlowString()
    {
        Print("Before");

        string otherResult = await OtherTask();

        return "GetSlow" + otherResult + await GetVerySlow(); ;
    }

    private Task<string> OtherTask()
    {
        return Task.Run(() =>
        {
            Print("Sleeping for 2s");
            Thread.Sleep(2 * 1000);
            Print("Sleeping done");
            return "OtherTaskResult";
        });
    }

    private Task<string> GetVerySlow()
    {
        Print("Inside");
        return Task.Run(() =>
        {
            Print("Sleeping 3s");
            Thread.Sleep(3000);
            Print("Sleeping Done");
            return "GetVerySlowReturn";
        });
    }
}
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
打印(“调用异步方法”);
runsomethingsync();
}
私有异步void runsomethingsync()
{
打印(“之前”);
字符串msg=await GetSlowString();
打印(“在”+消息之后);
cLabel.Content=msg;
}
作废打印(字符串消息,[CallerMemberName]字符串方法=”)
{
Print(“{0:N2}{1}{2}{3}”,DateTime.Now.Second,AppDomain.GetCurrentThreadId(),方法,消息);
}
专用异步任务GetSlowString()
{
打印(“之前”);
字符串otherResult=等待OtherTask();
返回“GetSlow”+其他结果+等待GetVerySlow();
}
私有任务OtherTask()
{
返回任务。运行(()=>
{
打印(“睡眠2秒”);
线程。睡眠(2*1000);
打印(“完成”);
返回“OtherTaskResult”;
});
}
私有任务GetVerySlow()
{
印刷品(“内部”);
返回任务。运行(()=>
{
打印(“睡眠3s”);
睡眠(3000);
打印(“完成”);
返回“GetVerySlowReturn”;
});
}
}

可能的重复当然有开销。但你的问题走错了方向。如果调用的任务很快,那么您可以在不使用异步的情况下同步调用它们。如果您想确定:Measure.@Alois-确切地说,在异步调用最后一个方法的同时,如何同步调用这些方法?我是异步编程的初学者,所以请随意改写我的文章。I3arnon解释了结构。一旦在任务内部运行,就不再需要异步模式,因为您的任务已经异步运行了。关于性能影响,请看我的答案。如果你不是在几微秒之后,而是在一个有响应的网页上,那么只要你在主线程上做你的工作,任何事情都可以做到。这总是会导致性能下降。当异步工作类似于阻塞IO时,您将获得可用性增益。但如果是朱