Вы путаете DI (или IoC) и IoC Container. Первый о том что класс не создает зависимости для самого себя. Второй - фреймворк который резолвит эти зависимости для класса. Прокидывает он их через конструктор (хорошо) или свойства (зло! Не делай так!). В статье используется так называемый Poor man DI. Пишу с телефона, лень умные ссылки добавлять. Если очень надо, то конечно добавлю.
Ненавижу удаленку. Времена короны были для меня испытанием. Я не люблю людей и большую часть дня в офисе я ни с кем не общаюсь, но там я чувствую себя гораздо комфортней. Думаю дело в размере помещения. В квартире на тебя давят стены и потолок. В офисе, пространство гораздо больше и огромные окна на всю стену.
Неужели вам нужно все разжевывать? Неужели не понятно что речь идет о том, что есть асинхронная версия с BeginInvoke? Мы в 2012, помните?Вместо того чтобы сосредотояится на главном, вы вылавливаете всякие закавырки не сказаные напрямую и придераетесь к ним, уходя от основной темы разговора. Просто поразительно насколько плохо у вас с абстрактным мышлением.
Статья Стивена Клери не появилась на пустом месте. В 2012 году C# показал людям что можно писать код, который выглядит как синхронный, но по факту имеет преимущества асинхронного. И людям было сложно понять эту магию. Все таки много лет они мыслили синхронными методами. Давайте возьмем простой пример, что бы понять в чем была сложность и почему появилась та статься.
Вот вам код:
public void DoSomeWork()
{
Console.WriteLine("Getting string...");
var str = GetString();
Console.WriteLine($"Received string {str}");
}
public string GetString()
{
var request = CreateRequest();
var response = ExecuteRequest(request);
var responseString = response.GetString();
return responseString;
}
Программист мыслил так:
Сначала мой код выведет `Getting string...`
Потом создаст запрос и отправит его на выполнение
Тут я буду ждать ответа, и только когда он вернется, я вытащу из него строку и выведу результат на экран
Это не эфективно, но зато прямоленейно, легко пишется и читается.
Я могу запустить ExecuteRequest асинхронно, но тогда мой код после этого вызова продолжит выполняться не дожидаясь ответа. То есть эти строки выполнятся хотя я еще не получил ответ:
var responseString = response.GetString();
return responseString;
Console.WriteLine($"Received string {str}");
Но это сломает программу поэтому мне нужно написать ее иначе. Нужно перекинуть продолжение в асинхронный колбэк. Если продолжение метода GetString это не сложно, то вот с DoSomeWork уже сложнее.
А что если перед DoSomeWork есть еще длиннющая цепочка вызовов?
Ну его нафиг, я просто использую синхронный вызов.
И тут приходит C# 5 и говорит: не надо менять структуру кода, просто добавть пару волшебных слов и все станет ассинхонным.
И программист такой: но как же так? Ведь response.GetString(); будет выполнен до окончания ExecuteRequest. Это сломает мой код!
C#: нет нет, твой код не продолжит выполнение. Он будет как бы заблокирован, но не заблокирован. Вот такая вот магия.
Программист: мне кажется ты лжешь. Ты запустишь где-то поток, который будет ждать ответа, а потом как-то вернешь управлнеие мне что бы я продолжил с того же места где закончил. Я не вижу колбэков! Кто-то должен дождаться ответа!
И вот это было самым сложным для понимания. Код выглядил линейным но выполнялся асинхронно. Все задавали этот вопрос, и Стивен прекрасно справился с ответом.
Вы опять делаете вброс не имеющий отношения к теме.
HttpRequestAsync - это асинхронный метод. Внутри он может вызывать цепочку из тысячи дополнительных асинхронных методов. Но вся эта цепочка будет выполняться синхронно и на одном и том же потоке(*) пока не дойдет до асинхронной операции. То есть той операции которая будет реально выполнять сетевой запрос. И вот только в тот момент когда запрос улетит в сеть, ваш поток будет освобожден.
И вот только тут начинается то ради чего мы собрались. Все что было до - не интересно. Здесь стоит вопрос: есть ли поток который будет ждать ответа из сети.
(*) я пометил это место звездочкой чтобы сразу отмести нелепые доводы, типа, если там будет `await Task.Run(...)`, или будет async метод, но без await и тому подобное. Речь не об этом.
Если это будет чисто вычислительный метод, но - помеченный как async и не забывающий время от времени делать await Task.Yield(), то он вполне может работать и в однопоточном контексте синхронизации...
Вы тут описали лабораторные условия, не имеющие никакого отношения к реальному коду в современном C#.
То есть, выполнение получается квази-параллельным
Вот именно. Квази-параллельным, но не асинхронными. Асинхронная операция, например сетевой запрос, будет выполняться в любом случае. Вам не надо писать код каким то особым способом чтобы она выполнялась. Вам лишь нужно написать специальный код, который примет ответ и продолжит дальше (раньше его писали вручную, а теперь это делает компилятор). В оригинальной статье стоял вопрос, есть ли поток, который будет выполнять эту операцию, и ответ был "нет такого потока". То есть совсем нет. Не в вашем процессе, не в операционной системе. Такого потока просто нет.
Автор же этой статьи исказил оригинальный вопрос, а потом опроверг ту статью дав ответ на свой искаженный вопрос. Он назвал это "субъективное мнение", и еще что-то там. Но как по мне, он просто не может признать что не верно понял вопрос, и продолжает зарывать себя еще глубже нелепыми отмазками.
The objectors to this truth are legion. “No,” they cry, “if I am awaiting an operation, there must be a thread that is doing the wait! It’s probably a thread pool thread. Or an OS thread! Or something with a device driver…”
Heed not those cries. If the async operation is pure, then there is no thread.
Код будет выполняться асинхронно в том смысле, что поток запустивший CPU-bound оерацию не будет ожидать ее завершения. Но эта операция не будет ассинхронной, она будет параллельной. Потому что для нее будет запущен отдельный поток, который будет работать в то время, как запустивший ее поток будет делать что-то другое. Понятия асинхронности и параллельности часто путают, потому что они не совсем ортогональны и если не впадать в формализм, бывают взаимозаменяемыми.
Асинхронный метод - это тот что помечен как async. Асинхронная операция - это грубо говоря I/O. Например чтение файла с диска (вот вам железо) или сетевой запрос (и это тоже железо). Эти операции выполняются какими-то там драйверами или еще чем, я не разбираюсь. Но точно знаю, что пока они выполняются, в .NET'овском коде не нужен поток который будет ждать их завершения. То есть, по сравнению с синхронными методами, выполняющими асинхронные операции, нужно гораздо меньше потоков что бы обслуживать большее число запросов. Потому что пока асинхронная операция не завершилась, ее поток может быть использован другим запросом. И об этом статья. Ваш же код, который как вы утверждаете, ее опровергает, совсем не о том. Так что выпад "я художник, я так вижу" - не уместен. Особенно если вы начали с высокомерного заявления намекая на то, что вы то во всем разобрались.
Логика тех, кто поддается такому внушению мне вполне понятна, они хотят упростить себе жизнь, сократить объем теории, с которой надо разбираться.
Интересно было бы понять логику тех, кто поддерживает такое внушение, выдавая обрезанную теорию за полноценную, вполне осознавая, что все не так просто, как хотелось бы.
Вот двое ваших предшественников так же рванули писать статью на Хабре, о том как круто они шарят и всех ща научат (спойлер: не научили)
Статья о том, что нет потока ожидающего завершения асинхронной операции. А не о том, будет ли выделен поток после завершения этой операции. Естественно после выполнения этой операции коду необходим поток для продолжения. В вашем примере вы фактически запускаете параллельно выполняющийся код (потому что нет await перед SomeMethodAsync1), которому естественно нужен поток.
Короче в этой заметке вы опровергли свое неверное понимание оригинальной статьи. Ни больше ни меньше.
А еще вы путаете понятия "асинхронная операция" с "асинхронным методом". Вообще не одно и то же.
Очередной разрушитель легенд, который не понимает разрушаемую легенду ?. И достаточно грубо отвечает тем, кто совершенно корректно объясниет где его ошибка ???
Вы путаете DI (или IoC) и IoC Container. Первый о том что класс не создает зависимости для самого себя. Второй - фреймворк который резолвит эти зависимости для класса. Прокидывает он их через конструктор (хорошо) или свойства (зло! Не делай так!). В статье используется так называемый Poor man DI. Пишу с телефона, лень умные ссылки добавлять. Если очень надо, то конечно добавлю.
А я думал чтобы как раз таки было можно. Без CORS все запрещено, а при включении CORS - немножечко можно.
То есть у вас не было ни одного хотя бы мидл разработчика, который бы вам сказал, что вы все не правильно делаете?
Не нужно.
И не нужно.
https://youtu.be/jOTM9T59IX4?si=23YQ3ECRo0lb2UYv
Ненавижу удаленку. Времена короны были для меня испытанием. Я не люблю людей и большую часть дня в офисе я ни с кем не общаюсь, но там я чувствую себя гораздо комфортней. Думаю дело в размере помещения. В квартире на тебя давят стены и потолок. В офисе, пространство гораздо больше и огромные окна на всю стену.
Какое соревнование? Вы о чем вообще? Этот коментарий такой же бессмысленный как и предыдущий. Как и ваши последние статьи, к слову.
На личность перешли? А еще ниже можете?
Хватит. То что вы перевели статью от Тауба про async/await не делает вас экспертом в этой теме. Хватить писать эту псевдонаучную ересь.
Неужели вам нужно все разжевывать? Неужели не понятно что речь идет о том, что есть асинхронная версия с BeginInvoke? Мы в 2012, помните?Вместо того чтобы сосредотояится на главном, вы вылавливаете всякие закавырки не сказаные напрямую и придераетесь к ним, уходя от основной темы разговора. Просто поразительно насколько плохо у вас с абстрактным мышлением.
Статья Стивена Клери не появилась на пустом месте. В 2012 году C# показал людям что можно писать код, который выглядит как синхронный, но по факту имеет преимущества асинхронного. И людям было сложно понять эту магию. Все таки много лет они мыслили синхронными методами. Давайте возьмем простой пример, что бы понять в чем была сложность и почему появилась та статься.
Вот вам код:
Программист мыслил так:
Сначала мой код выведет `Getting string...`
Потом создаст запрос и отправит его на выполнение
Тут я буду ждать ответа, и только когда он вернется, я вытащу из него строку и выведу результат на экран
Это не эфективно, но зато прямоленейно, легко пишется и читается.
Я могу запустить
ExecuteRequest
асинхронно, но тогда мой код после этого вызова продолжит выполняться не дожидаясь ответа. То есть эти строки выполнятся хотя я еще не получил ответ:Но это сломает программу поэтому мне нужно написать ее иначе. Нужно перекинуть продолжение в асинхронный колбэк. Если продолжение метода
GetString
это не сложно, то вот сDoSomeWork
уже сложнее.А что если перед
DoSomeWork
есть еще длиннющая цепочка вызовов?Ну его нафиг, я просто использую синхронный вызов.
И тут приходит C# 5 и говорит: не надо менять структуру кода, просто добавть пару волшебных слов и все станет ассинхонным.
И программист такой: но как же так? Ведь
response.GetString();
будет выполнен до окончанияExecuteRequest
. Это сломает мой код!C#: нет нет, твой код не продолжит выполнение. Он будет как бы заблокирован, но не заблокирован. Вот такая вот магия.
Программист: мне кажется ты лжешь. Ты запустишь где-то поток, который будет ждать ответа, а потом как-то вернешь управлнеие мне что бы я продолжил с того же места где закончил. Я не вижу колбэков! Кто-то должен дождаться ответа!
И вот это было самым сложным для понимания. Код выглядил линейным но выполнялся асинхронно. Все задавали этот вопрос, и Стивен прекрасно справился с ответом.
Вы опять делаете вброс не имеющий отношения к теме.
HttpRequestAsync
- это асинхронный метод. Внутри он может вызывать цепочку из тысячи дополнительных асинхронных методов. Но вся эта цепочка будет выполняться синхронно и на одном и том же потоке(*) пока не дойдет до асинхронной операции. То есть той операции которая будет реально выполнять сетевой запрос. И вот только в тот момент когда запрос улетит в сеть, ваш поток будет освобожден.И вот только тут начинается то ради чего мы собрались. Все что было до - не интересно. Здесь стоит вопрос: есть ли поток который будет ждать ответа из сети.
(*) я пометил это место звездочкой чтобы сразу отмести нелепые доводы, типа, если там будет `await Task.Run(...)`, или будет
async
метод, но безawait
и тому подобное. Речь не об этом.Вы тут описали лабораторные условия, не имеющие никакого отношения к реальному коду в современном C#.
Вот именно. Квази-параллельным, но не асинхронными. Асинхронная операция, например сетевой запрос, будет выполняться в любом случае. Вам не надо писать код каким то особым способом чтобы она выполнялась. Вам лишь нужно написать специальный код, который примет ответ и продолжит дальше (раньше его писали вручную, а теперь это делает компилятор). В оригинальной статье стоял вопрос, есть ли поток, который будет выполнять эту операцию, и ответ был "нет такого потока". То есть совсем нет. Не в вашем процессе, не в операционной системе. Такого потока просто нет.
Автор же этой статьи исказил оригинальный вопрос, а потом опроверг ту статью дав ответ на свой искаженный вопрос. Он назвал это "субъективное мнение", и еще что-то там. Но как по мне, он просто не может признать что не верно понял вопрос, и продолжает зарывать себя еще глубже нелепыми отмазками.
Код будет выполняться асинхронно в том смысле, что поток запустивший CPU-bound оерацию не будет ожидать ее завершения. Но эта операция не будет ассинхронной, она будет параллельной. Потому что для нее будет запущен отдельный поток, который будет работать в то время, как запустивший ее поток будет делать что-то другое. Понятия асинхронности и параллельности часто путают, потому что они не совсем ортогональны и если не впадать в формализм, бывают взаимозаменяемыми.
Не может. Она может быть параллельной, но не асинхронной.
Асинхронный метод - это тот что помечен как
async
. Асинхронная операция - это грубо говоря I/O. Например чтение файла с диска (вот вам железо) или сетевой запрос (и это тоже железо). Эти операции выполняются какими-то там драйверами или еще чем, я не разбираюсь. Но точно знаю, что пока они выполняются, в .NET'овском коде не нужен поток который будет ждать их завершения. То есть, по сравнению с синхронными методами, выполняющими асинхронные операции, нужно гораздо меньше потоков что бы обслуживать большее число запросов. Потому что пока асинхронная операция не завершилась, ее поток может быть использован другим запросом. И об этом статья. Ваш же код, который как вы утверждаете, ее опровергает, совсем не о том. Так что выпад "я художник, я так вижу" - не уместен. Особенно если вы начали с высокомерного заявления намекая на то, что вы то во всем разобрались.Вот двое ваших предшественников так же рванули писать статью на Хабре, о том как круто они шарят и всех ща научат (спойлер: не научили)
Разобраться раз и навсегда: Task.WhenAll или Parallel.ForEachAsync в C#
Как легко получить deadlock на Task.WhenAll
Статья о том, что нет потока ожидающего завершения асинхронной операции. А не о том, будет ли выделен поток после завершения этой операции. Естественно после выполнения этой операции коду необходим поток для продолжения. В вашем примере вы фактически запускаете параллельно выполняющийся код (потому что нет
await
передSomeMethodAsync1
), которому естественно нужен поток.Короче в этой заметке вы опровергли свое неверное понимание оригинальной статьи. Ни больше ни меньше.
А еще вы путаете понятия "асинхронная операция" с "асинхронным методом". Вообще не одно и то же.
Очередной разрушитель легенд, который не понимает разрушаемую легенду ?. И достаточно грубо отвечает тем, кто совершенно корректно объясниет где его ошибка ???