I don't understand exactly how expect / async works

I started learning Task, async / await concept - C # and I am having big trouble understanding it, well, at least I don't know how to implement it. I started to rewrite an old test program I wrote earlier, but now instead of streaming, I want to use these new concepts. Basically the layout is like this:

I have a simple class where I load HTML content in a web page. I am handling this in another class where basically just parsing the page with my model. Later I want to display this in my UI. The problem is my program is unresponsive, it blocks the UI while I process information.

I started looking into this 2 days ago, I read a lot on the internet including MSDN and some blogs, but I can't figure it out yet. Maybe someone can also take a look at

HtmlDOwnloadCOde:

public async Task<string> GetMangaDescriptionPage(string detailUrl)
{
    WebClient client = new WebClient();

    Stream data = await client.OpenReadTaskAsync(detailUrl);
    StreamReader reader = new StreamReader(data);
    string s = reader.ReadToEnd();
    data.Dispose();
    reader.Dispose();
    data.Close();
    reader.Close();
    return s;     
}

      

My parsing class code:

public async  Task<MangaDetailsModel> ParseMangaDescriptionPage()
{
    ParseOneManga pom = new ParseOneManga();
    string t1 = await pom.GetMangaDescriptionPage(selectedManga.url);
    HtmlDocument htmlDoc = new HtmlDocument();
        htmlDoc.LoadHtml(t1);
        var divs = htmlDoc.DocumentNode.Descendants("div").Where(x => x.Attributes.Contains("id") &&
            x.Attributes["id"].Value.Contains("title")).ToArray();
        mangaDetails.mangaName = divs[0].Element("h1").InnerText;

        mangaDetails.description = divs[0].Descendants("p").Single().InnerText ?? "DSA";
        var tds = divs[0].Descendants("td");
        int info = 0;

    var chapters = htmlDoc.DocumentNode.Descendants("div").Where(x => x.Attributes.Contains("id") &&
        x.Attributes["id"].Value.Contains("chapters")).ToArray();
    var chapterUi = chapters[0].Descendants("ul").Where(x => x.Attributes.Contains("class") &&
    x.Attributes["class"].Value.Contains("chlist"));
    foreach (var li in chapterUi)
    {
        var liChapter = li.Descendants("li");
        foreach (var h3tag in liChapter)
        {
            var chapterH3 = h3tag.Descendants("a").ToArray();
            SingleManagFox chapterData = new SingleManagFox();
            chapterData.name = chapterH3[1].InnerHtml;
            chapterData.url = chapterH3[1].GetAttributeValue("href", "0");
            mangaDetails.chapters.Add(chapterData);
        }
    };

    return mangaDetails;
}

      

UI code:

private async   void mainBtn_Click(object sender, RoutedEventArgs e)
{
    if (mangaList.SelectedItem != null)
    {
         test12((SingleManagFox)mangaList.SelectedItem);     
    }
}

private async void test12(SingleManagFox selectedManga)
{
    selectedManga = (SingleManagFox)mangaList.SelectedItem;
    MangaDetails mangaDetails = new MangaDetails(selectedManga);
    MangaDetailsModel mdm = await mangaDetails.ParseMangaDescriptionPage();
    txtMangaArtist.Text = mdm.artisName;
    txtMangaAuthor.Text = mdm.authorName;
    chapterList.ItemsSource = mdm.chapters;
}    

      

Sorry if its trivial, but I can't figure it out myself.

+3


source to share


2 answers


When switching to asynchronous mode, you need to try to switch to asynchronous mode completely and not mix blocking calls with asynchronous calls.

You are using async void

in an event handler without await

.

Try to avoid async void

unless it's an event handler. test12

must be updated to be returned Task

and expected in the event handler mainBtn_Click

.

private async void mainBtn_Click(object sender, RoutedEventArgs e) {
    if (mangaList.SelectedItem != null) {
       await test12((SingleManagFox)mangaList.SelectedItem);
    }
}

private async Task test12(SingleManagFox selectedManga) {
    selectedManga = (SingleManagFox)mangaList.SelectedItem;
    MangaDetails mangaDetails = new MangaDetails(selectedManga);
    MangaDetailsModel mdm = await mangaDetails.ParseMangaDescriptionPage();
    txtMangaArtist.Text = mdm.artisName;
    txtMangaAuthor.Text = mdm.authorName;
    chapterList.ItemsSource = mdm.chapters;
}  

      



Also consider updating the web call to use HttpClient

if available.

class ParseOneManga {
    public async Task<string> GetMangaDescriptionPageAsync(string detailUrl) {
        using (var client = new HttpClient()) {
            string s = await client.GetStringAsync(detailUrl);
            return s;                
        }
    }
}

      

Link: - the Async / Await - best practices in asynchronous programming

+1


source


Quite often people think that async-await means multiple threads are processing your code at the same time. This is not the case unless you explicitly start another thread.

A good metaphor that helped me a lot in explaining asynchronous waiting is the Restaurant metaphor used in this interview with Eric Lippert . Find somewhere in between for an asynchronous wait.

Eric Lippers compares handling asynchronous wait to a cook who has to wait while his water boils. Instead of waiting, he looks around if he can do other things instead. When he's finished doing something else, he returns to see if the water is boiling and begins to process the boiling water.

It's the same with your process. Takes only one thread (at a time). This thread continues to process until it has to wait for something. This is usually a fairly lengthy process that takes place without using your processor core, such as writing a file to disk, loading a web page, or requesting information from an external database.

Your theme can only do one thing at a time. So when it's busy calculating something if it can't respond to operator input and your UI freezes until the calculations are done. Waiting asynchronously will only help if your thread will wait many times for other processes to finish.

If you are calling an async function, you are sure there is waiting somewhere in that function. In fact, if you declare your async function and you forget to wait for it, your compiler will warn you.

When your call meets an expectation in a function, your thread raises the call stack to see if it can do other things. If you don't expect, you can continue processing until you can wait. The thread raises the call stack again to see if one of the callers is alive, etc.

async Task ReadDataAsync () {// make some preparations using (TextReader textReader = ...) {var myReadTask = textReader.ReadToEndAsync (); // while the text device is waiting for information to be available // you can do other things ProcessSomething ();



        // after a while you really need the results from the read data,
        // so you await for it.
        string text = await MyReadTask;
        // after the await, the results from ReatToEnd are available
        Process(text);
        ...

      

There are the following rules:

  • the async function should return Task

    instead of void and Task<TResult>

    instead ofTResult

  • There is one exception: the async event handler returns void instead Task

    .
  • Inside your async function, you have to wait somehow. If you don't expect it, it is useless to declare your async function
  • The result is await Task

    invalid and the result await Task<TResult>

    isTResult

  • If you are calling an async function see if you can do some processing instead of waiting for the call results

Note that even if you call multiple asynchronous functions before waiting for them, this does not mean that multiple threads execute those functions synchronously. The statement after your first call to the async function is processed after the called function starts waiting.

async Task DoSomethingAsync()
{
    var task1 = ReadAsync(...);
    // no await, so next statement processes as soon as ReadAsync starts awaiting
    DoSomeThingElse();

    var task2 = QueryAsync(...);
    // again no await

    // now I need results from bothtask1, or from task2:
    await Task.WhenAll(new Task[] {task1, task2});

    var result1 = Task1.Result;
    var result2 = Task2.Result;
    Process(result1, result2);
    ...

      

Usually all of your asynchronous functions are done in the same context. In practice, this means that you can program as if your program were single-threaded. This simplifies the look and feel of your program.

Another article that helped me understand asynchronous awaiting is Async-Await best practices written by the ever so helpful Stephen Cleary.

0


source







All Articles