ASP.NET - 异步编程

时间:2017-06-25 17:34:17

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

我正在尝试理解异步编程,我有一个问题。它涉及以下功能。

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调用只有在处理某些外部资源时才会相关吗?

2 个答案:

答案 0 :(得分:2)

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

  

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

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

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

  

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

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

答案 1 :(得分:2)

正如@ Stepehen-cleary所说,“特别是,异步和等待它们不会创建任何新线程。”

下一个例子来自John Skeet的书中的“C sharp in Depth”,第15章第466页:

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查询。

看看这个关于与异步任务并行的简短示例:

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
}