【问题标题】:ASP.NET - async programmingASP.NET - 异步编程
【发布时间】:2017-06-27 03:48:15
【问题描述】:

我想了解异步编程,但我有一个问题。它涉及以下功能。

public async void TestAsyncCall() {
Task<string> TaskResult1 = DoSomethingAsync();
string Result2 = DoSomething();
string Result1 = await TaskResult1; 
}

public string DoSomething() {
return "synch";
}

public async Task<string> DoSomethingAsync() {
await Task.Delay(10000);
return "asynch";
}

在函数调用TestAsyncCall()中,是不是一个线程执行DoSomethingAsync(),另一个线程执行DoSomething()?

那么当遇到 await 时,它会等待 DoSomethingAsync() 完成并释放该线程(同时也不阻塞原始线程)?

或者这不会保证创建任何新线程?在这种情况下,DoSomethingAsync 调用是否只有在处理某些外部资源时才相关?

【问题讨论】:

  • 异步编程并不总是与额外线程有关。您也可以等待计时器、磁盘或网络。这些都不会阻塞主线程,而代码在技术上是单线程的。这就是为什么异步活动的Task 抽象比线程更通用的原因。您甚至不需要经常考虑实际的实现是什么。
  • 你有async void。情况不妙。这是一面巨大的红旗。如果您有async void,您应该立即知道您遇到了问题。标记为async 的方法应始终返回TaskTask&lt;T&gt;(除非您实现了自己的特殊类型,请参阅the documentation)。
  • If you have async void you should immediately know you've got a problem 不一定是真的(虽然没有错),虽然这是一个糟糕的策略/设计,但async void 对于事件处理程序来说是不可避免的。

标签: c# asp.net asynchronous async-await


【解决方案1】:

我建议你阅读我在async ASP.NET 上的文章。

或者这不会保证创建任何新线程?

这不会创建任何新线程。特别是,asyncawait 本身不会创建任何新线程。

在 ASP.NET 上,await 的代码之后 可能会在与await 的代码之前 不同的线程上运行。不过,这只是将一个线程换成另一个线程;没有创建新线程。

在这种情况下,DoSomethingAsync 调用是否只有在处理某些外部资源时才相关?

async 的主要用例是处理 I/O,是的。在 ASP.NET 上尤其如此。

【讨论】:

    【解决方案2】:

    正如@Stepehen-cleary 所说,“特别是, async 和 await 本身不会创建任何新线程。”

    下一个例子取自 John Skeet 的“CSharp in Depth”一书,第 15 章 pp.465:

    class AsyncForm : Form
    {
        /* The first part of listing 15.1 simply creates the UI and hooks up an event handler for
           the button in a straightforward way */
        Label label;
        Button button;
        public AsyncForm()
        {
            label = new Label { 
                                Location = new Point(10, 20),
                                Text = "Length" 
                              };
            button = new Button {
                                    Location = new Point(10, 50),
                                    Text = "Click" 
                                };  
    
            button.Click += DisplayWebSiteLength;
            AutoSize = true;
            Controls.Add(label);
            Controls.Add(button);
        }   
    
    
        /*  When you click on the button, the text of the book’s home page is fetched
            and the label is updated to display the HTML lenght in characters */
        async void DisplayWebSiteLength(object sender, EventArgs e)
        {
            label.Text = "Fetching...";
            using (HttpClient client = new HttpClient())
            {
                string text =
                await client.GetStringAsync("http://csharpindepth.com");
                label.Text = text.Length.ToString();
            }
        }
        /*  The label is updated to display the HTML length in characters D. The
            HttpClient is also disposed appropriately, whether the operation succeeds or fails—
            something that would be all too easy to forget if you were writing similar asynchronous
            code in C# 4  */
    }
    

    考虑到这一点,让我们看一下您的代码,您有 Result1 和 Result2,让一个异步任务等待同步任务完成是没有意义的。我会使用Parallelism,这样您就可以执行这两种方法,但要返回两组数据,同时执行 LINQ 查询。

    看看这个关于 Parallelism with Async Tasks 的简短示例:

    public class StudentDocs 
    {
    
        //some code over here
    
        string sResult = ProcessDocs().Result;
    
        //If string sResult is not empty there was an error
        if (!sResult.Equals(string.Empty))
            throw new Exception(sResult);
    
        //some code over there
    
    
        ##region Methods   
    
        public async Task<string> ProcessDocs() 
        {
            string sResult = string.Empty;
    
            try
            {
                var taskStuDocs = GetStudentDocumentsAsync(item.NroCliente);
                var taskStuClasses = GetStudentSemesterClassesAsync(item.NroCliente, vencimientoParaProductos);
    
                //We Wait for BOTH TASKS to be accomplished...
                await Task.WhenAll(taskStuDocs, taskStuClasses);
    
                //Get the IList<Class>
                var docsStudent = taskStuDocs.Result;
                var docsCourses = taskStuClasses.Result;
    
               /*
                    You can do something with this data ... here
                */
            }
            catch (Exception ex)
            {
                sResult = ex.Message;
                Loggerdb.LogInfo("ERROR:" + ex.Message);
            }
        }
    
        public async Task<IList<classA>> GetStudentDocumentsAsync(long studentId)
        {
            return await Task.Run(() => GetStudentDocuments(studentId)).ConfigureAwait(false);
        }
    
        public async Task<IList<classB>> GetStudentSemesterCoursessAsync(long studentId)
        {
            return await Task.Run(() => GetStudentSemesterCourses(studentId)).ConfigureAwait(false);
        }
    
        //Performs task to bring Student Documents
        public IList<ClassA> GetStudentDocuments(long studentId)
        {
            IList<ClassA> studentDocs = new List<ClassA>();
    
            //Let's execute a Stored Procedured map on Entity Framework
            using (ctxUniversityData oQuery = new ctxUniversityData())
            {
                //Since both TASKS are running at the same time we use AsParallel for performing parallels LINQ queries
                foreach (var item in oQuery.GetStudentGrades(Convert.ToDecimal(studentId)).AsParallel())
                {
                    //These are every element of IList
                    studentDocs.Add(new ClassA(
                        (int)(item.studentId ?? 0),
                            item.studentName,
                            item.studentLastName,
                            Convert.ToInt64(item.studentAge),
                            item.studentProfile,
                            item.studentRecord
                        ));
                }
            }
            return studentDocs;
        }
    
        //Performs task to bring Student Courses per Semester
        public IList<ClassB> GetStudentSemesterCourses(long studentId)
        {
            IList<ClassB> studentCourses = new List<ClassB>();
    
            //Let's execute a Stored Procedured map on Entity Framework
            using (ctxUniversityData oQuery = new ctxUniversityData())
            {
                //Since both TASKS are running at the same time we use AsParallel for performing parallels LINQ queries
                foreach (var item in oQuery.GetStudentCourses(Convert.ToDecimal(studentId)).AsParallel())
                {
                    //These are every element of IList
                    studentCourses.Add(new ClassB(
                        (int)(item.studentId ?? 0),
                            item.studentName,
                            item.studentLastName,
                            item.carreerName,
                            item.semesterNumber,
                            Convert.ToInt64(item.Year),
                            item.course ,
                            item.professorName
                        ));
                }
            }
            return studentCourses;
        }
    
        #endregion
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-09-28
      • 2010-10-24
      • 2020-03-15
      • 2017-09-27
      • 1970-01-01
      • 2011-11-13
      • 2010-12-18
      • 1970-01-01
      相关资源
      最近更新 更多