简体   繁体   中英

ASP.NET - async programming

I am trying to understand async programming, and I had a question. It is regarding the following functions below.

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";
}

In the function call TestAsyncCall(), would one thread be used to execute DoSomethingAsync(), and another thread to execute DoSomething()?

Then when await is encountered, it would wait for DoSomethingAsync() to complete and release that thread (while also not blocking the original thread)?

Or will this not warrant any new threads being created? In that case will the DoSomethingAsync call be relevant only if it were to deal with some external resource?

I recommend you read my article on async ASP.NET .

Or will this not warrant any new threads being created?

This won't create any new threads. In particular, async and await by themselves won't create any new threads.

On ASP.NET, it's likely that the code after an await will run on a different thread than the code before that await . This is just exchanging one thread for another, though; no new threads are created.

In that case will the DoSomethingAsync call be relevant only if it were to deal with some external resource?

The primary use case for async is to deal with I/O, yes. This is particularly true on ASP.NET.

As @Stepehen-cleary said, "In particular, async and await by themselves won't create any new threads."

This next example is taken from the book: "C sharp in Depth" by John Skeet, chapter 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  */
}

With this in mind, let's take a look to your code, you have Result1 and Result2, there's no point in having one asynchronous task waiting for a synchronous task to be finished. I would use Parallelism so you can perform both methods but to return something like two sets of Data, performing LINQ queries at the same time.

Take a look to this short example about 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
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM