В .NET являются ли асинхронные методы исключительно теми, которые имеют ключевое слово async? - PullRequest
0 голосов
/ 18 января 2019

Я узнал о HttpClient (использование API в .NET в целом) и, следовательно, об асинхронном программировании. Я все еще довольно потерян, сейчас пытаюсь кое-что прояснить. Один вопрос, на который я не могу найти ответ - реализованы ли асинхронные методы исключительно с использованием ключевого слова async?

Я понимаю, что вы (теоретически) могли бы создавать синхронные методы, используя асинхронное программирование, но как вы это узнаете? Например, с эта ссылка и этот пример:

public string GetReleases(string url)
{
    using (var httpClient = new HttpClient())
    {
        httpClient.DefaultRequestHeaders.Add(RequestConstants.UserAgent, RequestConstants.UserAgentValue);

        var response = httpClient.GetStringAsync(new Uri(url)).Result;

        return response;
    }
}

Автор говорит:

Ради простоты я реализовал это синхронно

Но как мне распознать, что это синхронно? Только потому, что метод не определен с помощью асинхронной задачи, например:

public async Task<string> GetReleases(string url)

Значит ли это, что в этом учебном пособии по HttpClient этот пример также не асинхронный:

// GET: Student
    public ActionResult Index()
    {
        IEnumerable<StudentViewModel> students = null;

        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri("http://localhost:64189/api/");
            //HTTP GET
            var responseTask = client.GetAsync("student");
            responseTask.Wait();

            var result = responseTask.Result;
            if (result.IsSuccessStatusCode)
            {
                var readTask = result.Content.ReadAsAsync<IList<StudentViewModel>>();
                readTask.Wait();

                students = readTask.Result;
            }
            else //web api sent error response 
            {
                //log response status here..

                students = Enumerable.Empty<StudentViewModel>();

                ModelState.AddModelError(string.Empty, "Server error. Please contact administrator.");
            }
        }
        return View(students);
    }

Итак, подведем итог, мои вопросы:

  1. Асинхронное программирование (в .NET) и асинхронные методы реализованы исключительно с использованием async и void / Task / Task ?
  2. Если нет, то как иначе, и если да, то как распознать «истинные» асинхронные методы по сравнению с синхронными методами, реализованными с использованием асинхронных принципов (как в примере выше?)
  3. Почему тогда в приведенных выше примерах использовалась " синхронизация через асинхронную ", поскольку из всего, что я прочитал, все говорят НИКОГДА не делать этого? Являются ли они просто плохими примерами или для простоты (несмотря на это, не должно ли «правильный путь»> «простота»? Было бы нормально использовать это в ситуациях, когда, например, у меня очень простой код и я хочу избежать многопоточности Проблемы / deadlock, так как я пока не знаком с асинхронным программированием?

Ответы [ 3 ]

0 голосов
/ 18 января 2019
  1. Если метод возвращает Task или Task<T> (за исключением void в случае обработчика события), его можно ожидать и, следовательно, он может быть асинхронным. Ключевое слово async является лишь указанием на то, что оно может await где-то еще ждать Основываясь на потоке управления, async может вернуться, фактически ничего не ожидая. Асинхронное программирование не новость, оно существует во многих формах, таких как обратные вызовы, вызовы и т. Д.

  2. Приведенные вами примеры не правильно используют шаблон асинхронного ожидания. Microsoft предоставила соглашение об именах (Async Suffix) и Task<T>, Task в качестве типов для асинхронного программирования. Таким образом, если вы видите какой-либо метод, возвращающий Task<T> или Task, а имя метода имеет суффикс "Async", то вы можете считать его асинхронным. Хотя суффикс не требуется для компилятора, он помогает отличить его от синхронного аналога. (Read против ReadAsync)

  3. Это плохие примеры, эти действия должны быть помечены как асинхронные, и все результаты асинхронных методов следует ожидать для результата. В некоторых консольных программах может быть исключение, когда main не может быть асинхронным.

Пожалуйста, прочитайте Блог Стивена Клири об асинхронном ожидании

0 голосов
/ 18 января 2019

как я могу распознать истинно асинхронные / синхронизирующие методы?

Ты не можешь. На самом деле, нет. Вы можете определить методы, которые потенциально являются асинхронными, но мало что можно узнать без обращения к документации или реализации этих методов.

Итак, вы можете проверить тип возвращаемого значения метода. Если это void, вы мало что знаете. Если это Task, Task<T>, ValueTask<T> или любого другого ожидаемого типа 1 , то метод может быть асинхронным. Но имейте в виду, сигнатура метода может быть исправлена, потому что тип унаследовал метод от базового класса или реализует интерфейс; Поэтому, хотя метод потенциально может быть асинхронным, фактическая реализация этого метода может быть полностью синхронной.

Или, метод может иметь потенциал быть асинхронным, но может иметь определенные потоки управления, которые приводят к тому, что он ведет себя синхронно 2 . Это могут быть, например, что если определенные условия выполняются, у метода уже есть ответ, поэтому он сразу его возвращает. В противном случае он отключается и выполняет что-то асинхронное - как один из примеров.

Если возвращаемый тип не является ожидаемым и не является пустым, все, что вы можете на самом деле рассуждать о методе, это то, что в точке, в которой он возвращается, ему предоставляется некоторое значение для этого возвращаемого типа 3 . Нет никакого способа рассуждать о какой-либо другой работе , которая могла быть запущена этим методом - только то, что если она сделала что-то подобное, она не предполагает, что вы сможете узнать, когда эта работа будет завершена .


Если вы смотрите на реализацию метода и спрашиваете себя «является ли эта реализация асинхронной», тогда важно выяснить, что делает этот код после того, как элемент управления возвращается обратно вызывающей стороне. ,

Когда управление возвращается обратно вызывающей стороне?

  • Когда мы нажмем return
  • Когда мы нажимаем await, возможно

Когда мы нажимаем await, мы возвращаем управление обратно вызывающей стороне 4 , если ожидание того, что мы await не завершены. Таким образом, мы должны выяснить, откуда появилось это ожидаемое, и, если это произошло из-за вызова другого метода, мы должны начать все заново, чтобы рассмотреть, что делает этот метод.

Если метод содержит await с, то, как правило, безопаснее сказать, что он потенциально асинхронный - но имейте в виду вышеупомянутые возможности относительно уже завершенных ожидаемых и ранних return с.

Если это не async / await, что еще он мог бы сделать? Что ж, если он работает с Task s, возможно, он создал одну или несколько из этих задач, чтобы представить текущую работу. Возможно, было запланировано больше кода для запуска через ContinueWith.

Если он не работает с Task напрямую, не вызвал что-то еще, что потенциально асинхронно, не вызвало создание нового Thread и не было бесполезно запутано, это , вероятно синхронно.


Можно ли использовать это в ситуациях, когда, например, у меня очень простой код и я хочу избежать проблем с многопоточностью / взаимоблокировкой, так как я пока не знаком с асинхронным программированием?

Синхронизация по асинхронным шаблонам, показанным в примерах в вашем вопросе, на больше подвержена взаимным блокировкам, чем работа с async / await. Зачем? Потому что они блокируют текущий поток , ожидая, когда произойдут другие события. Но текущий поток или ресурсы, которые он заблокировал, могут быть особыми - и фактическим асинхронным задачам, которые он вызывает, может потребоваться получить доступ к тому же потоку / ресурсу, прежде чем они смогут завершиться. Классический тупик.


1 Awaitable - одно из многих мест, где C # использует "типизацию утки". Если есть метод (экземпляр или расширение) с именем GetAwaiter, который возвращает тип с правильной формой, это приемлемо. Поэтому, несмотря на то, что вы, вероятно, никогда не увидите его, имейте в виду, что пользовательские ожидаемые значения возможны в языке.

2 На ум приходят "горячие пути".

3 И out / ref Параметры. Конечно, если он есть, это не будет асинхронный метод, реализованный через ключевые слова async / await, но он все равно может иметь асинхронное поведение.

4 Если мы уже передали управление обратно вызывающей стороне во время более раннего await, мы не вернем управление обратно вызывающей стороне через await с, но мы будем возвращая это «чему-то», которое не является нашим кодом.

0 голосов
/ 18 января 2019

Асинхронный метод в C # может возвращать void, Task или Task<T>, где следует вообще избегать void, поскольку его нельзя ожидать.

Как правило, асинхронные методы должны называться DoSomethingAsync()

Ключевое слово async, однако, является подробностью реализации и не относится к API. Это ключевое слово требуется только в том случае, если вы используете await в теле метода. Но это не обязательно так. Вы можете просто делегировать другому асинхронному методу, без необходимости помечать метод как async и использовать await.

Таким образом, «истинные» асинхронные методы должны распознаваться суффиксом Async имени метода, однако вы не можете быть уверены, что разработчик фактически использует естественные асинхронные операции или даже выполняет синхронно некоторые части или весь метод.

В примере он сделал метод синхронно, поставив .Result в конце GetStringAsync

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...