async / await не работает должным образом - PullRequest
0 голосов
/ 06 мая 2018

У меня проблема с моим методом async / await. Я новичок в async / await и, кажется, не могу заставить его работать правильно.

GUI зависает, когда у меня появляется следующее.

private async void SetUpTextBox(string s)
{
    //This method is called in button event
    string textToSet = await GetTextA(s);
    read_Box.Text = textToSet;
}

private Task<string> GetTextA(string s)
{
    return Task.Run(() => GetText(s));
}

private string GetText(string s)
{
    string textToReturn = "Hello";
    using (StreamReader sr = new StreamReader(File.OpenRead(s)))
    {
        textToReturn = sr.ReadToEnd();
    }
    return textToReturn;
}

Я не знаю, что я делаю неправильно. Я знаю, что я новичок в этом, и поэтому я здесь, чтобы учиться (a.k.a не судите!).

P.S Когда я пытался изменить

using (StreamReader sr = new StreamReader(File.OpenRead(s)))
{
    textToReturn = sr.ReadToEnd();
}

С простым Thread.Sleep(2500) методом. GUI вообще не зависает!

Ответы [ 3 ]

0 голосов
/ 06 мая 2018

Избегайте async void за исключением асинхронных обработчиков событий, плюс вы можете использовать ReadToEndAsync и делать код асинхронным до конца.

private async Task SetUpTextBox(string s) {
    //This method is called in button event
    string textToSet = await GetTextAsync(s);
    read_Box.Text = textToSet;
}

private async Task<string> GetTextAsync(string s) {
    string textToReturn = "Hello";
    using (StreamReader sr = new StreamReader(File.OpenRead(s))) {
        textToReturn = await sr.ReadToEndAsync();
    }
    return textToReturn;
}

Пример вызова SetUpTextBox в обработчике событий нажатия кнопки, как следует из комментария из исходного сообщения

public async void OnBtnClicked(object sender, EventArgs args) {
    try {
        //...

        await SetUpTextBox("some path");

        //..
    } catch {
        //... handle error
    }
}

Вы также должны поставить try/catch вокруг всегос помощью асинхронного обработчика void, в противном случае любые исключения останутся незамеченными.

Ссылка Async / Await - Лучшие практики асинхронного программирования

0 голосов
/ 06 мая 2018

Прежде всего, то, что вы должны делать, а вы нет:

  • Использование ReadToEndAsync.
  • Как избежать Task.Run, когда задача не связана с процессором.
  • Как избежать async void, когда метод не является обработчиком событий.
  • Правильная обработка ошибок.

Нкоси проделал приличную работу, иллюстрируя это.

Осталось объяснить, почему Thread.Sleep(2500) не блокирует пользовательский интерфейс.


Прежде всего, обратите внимание, что Task.Run будет запускать задачу, используя ThreadPool.

Вы можете проверить, что System.Threading.Thread.CurrentThread.IsThreadPoolThread истинно внутри GetText (например, вы можете установить точку останова и использовать проверки для проверки).

Это означает, что поток пользовательского интерфейса не может быть заблокирован внутри GetText, поскольку поток пользовательского интерфейса не запускается GetText.


Но почему тогда Thread.Sleep(2500); дает другой результат?

Хммм ... какая разница между:

private string GetText(string s)
{
    string textToReturn = "Hello";
    using (StreamReader sr = new StreamReader(File.OpenRead(s)))
    {
        textToReturn = sr.ReadToEnd();
    }
    return textToReturn;
}

И

private string GetText(string s)
{
    string textToReturn = "Hello";
    Thread.Sleep(2500);
    return textToReturn;
}

Позвольте мне сказать вам:

  • Возможны исключения. Поскольку вы не обрабатываете их - и я предполагаю, что вы используете отладочную сборку в отладчике - вы бы заметили. Поэтому я не думаю, что это проблема. Даже если вы этого не сделаете, исключения не из потока пользовательского интерфейса, они останутся необработанными и приведут к аварийному завершению приложения (Редактировать: я тестировал).
  • Количество времени, необходимое для выполнения. Однако, поскольку пользовательский интерфейс не будет заблокирован этим кодом - если он работает в ThreadPool - это тоже не так.
  • Количество возвращенного текста.

Когда вы устранили невозможное, все, что остается, каким бы невероятным оно ни было, должно быть истиной

- Шерлок Холмс

Пользовательский интерфейс застрял, потому что вы возвращаете слишком много текста.


Позвольте мне сказать вот так ...

СЛИШКОМ МНОГО ТЕКСТА ВОЗВРАЩЕНО

private string GetText(string s)
{
    string textToReturn = "Hello";
    using (StreamReader sr = new StreamReader(File.OpenRead(s)))
    {
        textToReturn = sr.ReadToEnd();
    }
    return textToReturn;
}

Возвращен небольшой текст:

private string GetText(string s)
{
    string textToReturn = "Hello";
    Thread.Sleep(2500);
    return textToReturn;
}

Пользовательский интерфейс, следовательно, застрял на read_Box.Text = textToSet;, занятом рендерингом всего текста, который вы получили из файла. Или, по крайней мере, это мой гипотез.

0 голосов
/ 06 мая 2018

Создайте асинхронную пустоту (например, Wait) с Thread.Sleep (x) внутри и вызовите его с помощью «await Wait (x);» внутри асинхронной пустоты.

...