S> И в чем проблема? .ConfigureAwait(false) гарантирует что будет игнорироваться Контекст синхронизации, и не будет переключаться на поток GUI. S>Просто по умолчанию .ConfigureAwait(true), что приводит к дедлокам
А false к эксепшенам? тут можно ещё предложить вынести все эти true/false в конфиг. А конфиг генерить самообучающейся сетью которая по дедлокам/эксепшенам/сигнатурам методов будет предлагать правильные значения
Плюс для тестеров апгрейд — раньше они просто тестировали, а теперь будут фактически воспитывать.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Здравствуйте, Serginio1, Вы писали:
S> Да? Весь интернет ими усыпан.
Благодаря советам в форме категорического императива
S> Именно для GUI по умолчанию асинхронные методы превращаются в синхронные там где это и не надо, по тому, что по умолчанию .ConfigureAwait(true).
Очень показательное слово выбрал — "превращаются". Магия, да? И взмах волшебной палочки в виде ConfigureAwait нам поможет. Ну что-ж, удачи в лечении симтомов, а не болезни.
Здравствуйте, TK, Вы писали: TK>А false к эксепшенам? тут можно ещё предложить вынести все эти true/false в конфиг. А конфиг генерить самообучающейся сетью которая по дедлокам/эксепшенам/сигнатурам методов будет предлагать правильные значения
TK>Плюс для тестеров апгрейд — раньше они просто тестировали, а теперь будут фактически воспитывать.
Ну то есть везде в библиотеках лепить ConfigureAwait(false), на случай вызова из GUI это нормально?
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>>Поэтому правильно делать так. S>Неправильно делать так.
S>.ConfigureAwait(true) приводит к вызову S>
S>обычный await заканчивается тем же.
S>Таки советую сначала изучить матчасть, а затем уже рассуждать про правильно/неправильно. Порядок важен
Угу ты бы хоть раз прочитал, что я пушу. Я как раз и пишу, что по умолчанию ConfigureAwait(true), а нужно наоборот, что бы возвращаться в поток GUI тогда когда это нужно для установки значений контролов.
Просто когда пишешь код для xamarin, WPF , 1C нужно учитывать этот контекст синхронизации там где он есть и там где его нет писать ConfigureAwait(false). S>P.S. Поправь оверквотинг в ответах. Читать же неудобно
Я знаю. Именно пишу ConfigureAwait(true), что по уму нужно по умолчанию как раз ConfigureAwait(false), а ConfigureAwait(true) там, где нужно реально переключаться на поток GUI/
И всем кто пишет в GUI это будет понятно. А так любой await по умолчанию нужно это или не нужно переключается на поток GUI/
и солнце б утром не вставало, когда бы не было меня
S>> Именно для GUI по умолчанию асинхронные методы превращаются в синхронные там где это и не надо, по тому, что по умолчанию .ConfigureAwait(true).
_R_>Очень показательное слово выбрал — "превращаются". Магия, да? И взмах волшебной палочки в виде ConfigureAwait нам поможет. Ну что-ж, удачи в лечении симтомов, а не болезни.
Болезнь как раз в том, что await по умолчанию .ConfigureAwait(true) когда возвращается в поток GUI где надо и где не надо.
А программист это волшебник. Ты разве не знал?
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> Я знаю. Именно пишу ConfigureAwait(true), что по уму нужно по умолчанию как раз ConfigureAwait(false), а ConfigureAwait(true) там, где нужно реально переключаться на поток GUI/
Первое правило любого предложения в стиле "а давайте сделаем так": посмотри на последствия.
Сейчас await task.ConfigureAwait(true); идентичен по поведению простому await task;. Это решение абсолютно правильно, т.к поведение заточено под конечных пользователей.
В твоём варианте большинство клиентского кода или содержало бы баги, или было бы отравлено копипастой с .ConfigureAwait. Это очень плохое решение, поэтому в фреймворк оно не прошло.
P.S. Напоминаю: S>>P.S. Поправь оверквотинг в ответах. Читать же неудобно
Капсом писать что ли?
(rsdn позволяет редактировать ответы, если что).
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>> Я знаю. Именно пишу ConfigureAwait(true), что по уму нужно по умолчанию как раз ConfigureAwait(false), а ConfigureAwait(true) там, где нужно реально переключаться на поток GUI/ S>Первое правило любого предложения в стиле "а давайте сделаем так": посмотри на последствия.
Я как раз и смотрю и вижу косяки. При этом никто не знает про ConfigureAwait S>Сейчас await task.ConfigureAwait(true); идентичен по поведению простому await task;. Это решение абсолютно правильно, т.к поведение заточено под конечных пользователей. S>В твоём варианте большинство клиентского кода или содержало бы баги, или было бы отравлено копипастой с .ConfigureAwait. Это очень плохое решение, поэтому в фреймворк оно не прошло.
Большинство клиентского кода как раз потому, что сделали ConfigureAwait(true) по умолчанию и никто не знает про существование ConfigureAwait. И весь интернет усыпан вопросами о дедлоках.
При этом не везде в клиентском коде нужно переключатся на поток контекста.
При этом в ошибки установки свойств контрола в не потоке GUI можно возвращать ошибку про использовании ConfigureAwait, а с дедлоком вообще ничего не выдается.
S>P.S. Напоминаю: S>>>P.S. Поправь оверквотинг в ответах. Читать же неудобно
S>Капсом писать что ли? S>(rsdn позволяет редактировать ответы, если что).
Правлю.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
TK>>Плюс для тестеров апгрейд — раньше они просто тестировали, а теперь будут фактически воспитывать. S> Ну то есть везде в библиотеках лепить ConfigureAwait(false), на случай вызова из GUI это нормально?
Главное, это настройки в конфиг вынести. А дальше, можно просто по подстроке — если метод содержит click то, по умолчанию true, а если run то false. Ну или наоборот
Можно и рандомом раскидать — опытный тестер / конфигуратор / воспитатель сам все настроит как считает нужным.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Здравствуйте, TK, Вы писали:
TK>Здравствуйте, Serginio1, Вы писали:
TK>>>Плюс для тестеров апгрейд — раньше они просто тестировали, а теперь будут фактически воспитывать. S>> Ну то есть везде в библиотеках лепить ConfigureAwait(false), на случай вызова из GUI это нормально?
TK>Главное, это настройки в конфиг вынести. А дальше, можно просто по подстроке — если метод содержит click то, по умолчанию true, а если run то false. Ну или наоборот TK>Можно и рандомом раскидать — опытный тестер / конфигуратор / воспитатель сам все настроит как считает нужным.
Кстати а можно указать для компилятора, что по умолчанию ConfigureAwait(false)?
Просто для библиотек это было бы удобно.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>>Первое правило любого предложения в стиле "а давайте сделаем так": посмотри на последствия. S> Я как раз и смотрю и вижу косяки.
Не вопрос, какие именно косяки?
S> Большинство клиентского кода как раз потому, что сделали ConfigureAwait(true) по умолчанию и никто не знает про существование ConfigureAwait. И весь интернет усыпан вопросами о дедлоках.
А можно пример? Есть такое подозрение, что проблема там не в ConfigureAwait(), а в исчерпании потоков, доступных для запуска продолжений. Так это и с ConfigureAwait(false) можно устроить, дурное дело нехитрое
S>При этом не везде в клиентском коде нужно переключатся на поток контекста.
По умолчанию — везде. Если, конечно, не хочется ловить баги типа "опс, культура не та" в самом неожиданном месте.
S> При этом в ошибки установки свойств контрола в не потоке GUI можно возвращать ошибку про использовании ConfigureAwait, а с дедлоком вообще ничего не выдается.
Не вопрос, давай с всё тем же кодом из примера выше. Есть идеи, как заставить его выдавать ошибку стандартными средствами фреймворка? Не ломая совместимости.
Напоминаю, исключение по факту бросается в фоновом потоке.
И после этого — как быть с ошибками, не связанными с обращением к UI?
S> Правлю.
Спасиб
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>>>Первое правило любого предложения в стиле "а давайте сделаем так": посмотри на последствия. S>> Я как раз и смотрю и вижу косяки. S>Не вопрос, какие именно косяки?
Да постоянные вопросы из-за дедлоков
S>> Большинство клиентского кода как раз потому, что сделали ConfigureAwait(true) по умолчанию и никто не знает про существование ConfigureAwait. И весь интернет усыпан вопросами о дедлоках. S>А можно пример? Есть такое подозрение, что проблема там не в ConfigureAwait(), а в исчерпании потоков, доступных для запуска продолжений. Так это и с ConfigureAwait(false) можно устроить, дурное дело нехитрое
Так я тебе в твоем примере и привел, когда при вызове RunAsync внутри ты будешь не будешь использовать ConfigureAwait(false)
Просто ты не читаешь.
private async Task Button_Click(object sender, RoutedEventArgs e)
{
await RunAsync().Wait(); //1
button.Content = "x_X";
MessageBox.Show("Completed:" + t.IsCompleted));
}
private async Task RunAsync()
{
await Task.Delay(1); //2 Получим классический дедлок
// Так как await Task.Delay(1); возвращается в поток GUI но, await RunAsync() его ждет
}
Клик по кнопке здесь приводит к дедлоку. UI поток стартует новый I/O поток на строке «2» и уходит в спящий режим на строке «1», ожидая завершения работы. После того как I/O поток заканчивает выполнение, оставшаяся часть метода RunAsync передается на выполнение вызывающему (UI) потоку. Но тот в это время находится в спящем режиме, ожидая завершения метода. Дедлок.
S>>При этом не везде в клиентском коде нужно переключатся на поток контекста. S>По умолчанию — везде. Если, конечно, не хочется ловить баги типа "опс, культура не та" в самом неожиданном месте.
Вот именно. Но это бывает не всегда. А народ про ().ConfigureAwait(false); вообще не знает
S>> При этом в ошибки установки свойств контрола в не потоке GUI можно возвращать ошибку про использовании ConfigureAwait, а с дедлоком вообще ничего не выдается. S>Не вопрос, давай с всё тем же кодом из примера выше. Есть идеи, как заставить его выдавать ошибку стандартными средствами фреймворка? Не ломая совместимости. S>Напоминаю, исключение по факту бросается в фоновом потоке.
Не ломая совместимости можно для библиотек сделать опцию для компилятора или проекта ConfigureAwait(false) по умолчанию. S>И после этого — как быть с ошибками, не связанными с обращением к UI?
А все также и остается. Но проблема дедлоков и лишней писанины убирается. S>> Правлю. S>Спасиб
Все посыпаю голову пеплом! Что то я совсем заработался. Проблема с Result.
Я в 1С не могу вызвать await поэтому мне приходится вызывать Result, а он как раз и ведет к дедлоку.
У всех прошу прощения и удаляюсь в монастырь.
Но вот сделать опцию для ConfigureAwait(false); стоит
и солнце б утром не вставало, когда бы не было меня
Все посыпаю голову пеплом! Что то я совсем заработался. Проблема с Result.
Я в 1С не могу вызвать await поэтому мне приходится вызывать Result, а он как раз и ведет к дедлоку.
А вызывать через события муторно.
У всех прошу прощения и удаляюсь в монастырь.
Но вот сделать опцию для ConfigureAwait(false); стоит
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> Так я тебе в твоем примере и привел, когда при вызове RunAsync внутри ты будешь не будешь использовать ConfigureAwait(false) S>Просто ты не читаешь.
Скорее наоборот Цитато:
проблема там не в ConfigureAwait(), а в исчерпании потоков, доступных для запуска продолжений
Код await RunAsync().Wait(); именно это и делает — блокирует все доступные потоки (их одна штука). Вот тебе другой пример того же поведения:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
ThreadPool.SetMinThreads(1, 1);
ThreadPool.SetMaxThreads(8, 8);
// ...
RunAsync(10).Wait();
Console.WriteLine(total);
}
private static volatile int total = 0;
private static async Task RunAsync(int i)
{
if (i == 0)
return;
Console.WriteLine(i);
await Task.Delay(1).ConfigureAwait(false);
RunAsync(i - 1).Wait();
Interlocked.Increment(ref total);
}
}
}
Ну как, помог ConfigureAwait(false)?
Надеюсь, теперь понятно, про что уже четыре человека в топике пытаются тебе намекнуть: не надо лечить симптомы, не разобравшись с болезнью.
Вот дался тебе тот минус? Это ж не способ оценить автора, это намёк на "с сообщением не согласен, но расписывать лень". Может правда лень, может аргументов просто нет, не надо на это обращать внимания. Убрал, тем более что сигнал уже дошёл
Если про минус на ru.stackoverflow.com, то ты точно меня с кем-то перепутал. Я на русскоязычном вообще не отмечаюсь, да и на основном отвечаю очень редко.
S> Вот именно. Но это бывает не всегда. А народ про ().ConfigureAwait(false); вообще не знает
И оно отлично работает, если самому не раскладывать грабли. Причём это можно сделать кучей способов, от которых ConfigureAwait не спасёт, пример выше. Ну а после наступания народ сразу познаёт дао и больше так не делает. Куда не погляди — везде плюсы
S>> Вот именно. Но это бывает не всегда. А народ про ().ConfigureAwait(false); вообще не знает S>И оно отлично работает, если самому не раскладывать грабли. Причём это можно сделать кучей способов, от которых ConfigureAwait не спасёт, пример выше. Ну а после наступания народ сразу познаёт дао и больше так не делает. Куда не погляди — везде плюсы
Ну я уже извинился. Но даже при этом считаю, что нужна опция для ConfigureAwait(false); для библиотек. Например в 1С я не могу использовать await.
И во многих случаях переключать контекст не стоит, но из-за того, что ConfigureAwait(true); просто мы теряем в производительности на переключение потока и ожидание когда основной поток GUI освободится, там где нам не нужно использовать контролы.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>> Так я тебе в твоем примере и привел, когда при вызове RunAsync внутри ты будешь не будешь использовать ConfigureAwait(false) S>>Просто ты не читаешь.
S>Скорее наоборот Цитато: S>
S>проблема там не в ConfigureAwait(), а в исчерпании потоков, доступных для запуска продолжений
S>Код await RunAsync().Wait(); именно это и делает — блокирует все доступные потоки (их одна штука). Вот тебе другой пример того же поведения:
Еще раз. Я в 1С использую Контекст Синхронизации для получения ком событий в потоке GUI 1c. S>
Вот такого выделенного я в 1С не могу сделать, а в вот вместо выделенного в библиотеке
await RunAsync(i - 1).Wait;
await RunAsync(i — 1) легко S>Надеюсь, теперь понятно, про что уже четыре человека в топике пытаются тебе намекнуть: не надо лечить симптомы, не разобравшись с болезнью.
Я уже 1000+1 раз объяснил свою проблему в 1С. Но Вы не слушаете. Огромное спасибо за ConfigureAwait.Fody
Еще раз не везде можно использовать await, но можно использовать WindowsFormsSynchronizationContext и для получения результата использовать методы синхронизации.
Мне это нужно, а вам нет. Но это не значит, что проблемы не существует.
Поэтому, если у Вас не болит, то это не значит, что не болит у всех
Да и в GUI далеко не всегда нужно переключаться на поток GUI. Раньше до await использовали Invoke
delegate void AddTextToTListBox(string text);
void msg_OnSendChatMessage(string message)
{
if (listBox1.InvokeRequired)
{
AddTextToTextBox d = new AddTextToTextBox(msg_OnSendChatMessage);
this.Invoke(d, new object[] { message });
}
else
{
listBox1.Text += message + "\r\n";
}
}
И это было нормально. А вот ConfigureAwait(true) это уже извращение.
Еще раз огромное спасибо за ConfigureAwait.Fody. Это решение всех моих проблем.
Но к сожалению, не решает проблем со сторонними библиотеками где не используют .ConfigureAwait(false);
и солнце б утром не вставало, когда бы не было меня