Гость
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / От чего может виснуть этот код? / 25 сообщений из 44, страница 1 из 2
07.04.2021, 20:39
    #40060522
От чего может виснуть этот код?
Примерно так:

В form_Load:

Код: c#
1.
2.
3.
4.
5.
6.
new Task(async () =>
{
  await LoadSomeEntities1().ConfigureAwait(false);
  await LoadSomeEntities2().ConfigureAwait(false);
  await LoadSomeEntities3().ConfigureAwait(false);
}).RunSynchronously();



Форма загружается, всё отрабатывает, всё загружено. Никаких проблем!

В combobox_selectedIndexChanged:

Код: c#
1.
LoadSomeEntities3().ConfigureAwait(false).GetAwaiter().GetResult();



А в самой функции:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
async Task LoadSomeEntities3()
{
  trvTreeView.SuspendLayout();
  trvTreeView.BeginUpdate();
  trvTreeView.Nodes.Clear();

  await ReadEntitesFromDB().ConfigureAwait(false); // Но если здесь убрать await и добавить .GetAwaiter().GetResult(), то не виснет
  foreach(var entity in entities)
  {
    if(trvTreeView.InvokeRequired)
    {
      trvTreeView.Invoke((MethodDelegate) delegate // виснет здесь только при выборе значения в комбобоксе
      {
        trvTreeView.Nodes.Add(entity.Name);
      });
    }
    else
    {
       trvTreeView.Nodes.Add(entity.Name);
    }
  }

  if(trvTreeView.InvokeRequired)
  {
    trvTreeView.Invoke((MethodDelegate) delegate 
    {
      trvTreeView.EndUpdate();
      trvTreeView.ResumeLayout();
    }
  }
  else
  {
    trvTreeView.EndUpdate();
    trvTreeView.ResumeLayout();
  }
}



Но стоит сменить значение комбобокса, как тот же самый код виснет на входе в делегат. Чем отличается вызов этого кода при пользовательском вводе от вызова при загрузке формы?

В обоих случаях InvokeRequired = true, соответственно всегда отрабатывает делегат.
...
Рейтинг: 0 / 0
07.04.2021, 21:45
    #40060529
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
Бариску Нацарство
Код: c#
1.
await ReadEntitesFromDB().ConfigureAwait(false); // Но если здесь убрать await и добавить .GetAwaiter().GetResult(), то не виснет



потому что так делать нельзя, объяснять долго, нудно, всё это можно найти и почитать в документации.

непонятно зачем так делаете, это просто эксперименты?

https://stackoverflow.com/questions/5095183/how-would-i-run-an-async-taskt-method-synchronously
...
Рейтинг: 0 / 0
07.04.2021, 23:08
    #40060540
От чего может виснуть этот код?
что значит нельзя? так делают все и везде. в чём конкретно претензия?
и зачем мне ссылка на синхронное исполнение асинхронного вызова? синхронно-то оно и так работает.
...
Рейтинг: 0 / 0
07.04.2021, 23:23
    #40060548
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
Бариску Нацарство
что значит нельзя?


то и значит.

Бариску Нацарство
так делают все и везде. в чём конкретно претензия?


Код: c#
1.
2.
3.
4.
5.
6.
new Task(async () =>
{
  await LoadSomeEntities1().ConfigureAwait(false);
  await LoadSomeEntities2().ConfigureAwait(false);
  await LoadSomeEntities3().ConfigureAwait(false);
}).RunSynchronously();



так даже в дремучем колхозе делать моветон.


Бариску Нацарство
и зачем мне ссылка на синхронное исполнение асинхронного вызова? синхронно-то оно и так работает.


у вас асинхронный метод

Код: c#
1.
async Task LoadSomeEntities3()



зачем вы в этом методе асинхронный метод пытаетесь вызвать "синхронно"?

Код: c#
1.
await ReadEntitesFromDB().ConfigureAwait(false); // Но если здесь убрать await и добавить .GetAwaiter().GetResult(), то не виснет



зачем убирать await и добавлять GetResult()? это во-первых неправильно, что как бы подтверждается тем, что "виснет", во-вторых.. зачем? это для чего?
...
Рейтинг: 0 / 0
07.04.2021, 23:24
    #40060549
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
Бариску Нацарство,

и зачем вы везде .ConfigureAwait(false) добавляете? при чём там, где как раз этого делать нельзя.
...
Рейтинг: 0 / 0
07.04.2021, 23:58
    #40060553
petalvik
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
Бариску Нацарство,

Код: c#
1.
2.
3.
4.
5.
6.
private async void Form1_LoadAsync(object sender, EventArgs e)
{
    await LoadSomeEntities1().ConfigureAwait(false);
    await LoadSomeEntities2().ConfigureAwait(false);
    await LoadSomeEntities3().ConfigureAwait(false);
}


Не нужно их оборачивать в Task и запускать синхронно.
При желании, можно написать так:

Код: c#
1.
2.
3.
4.
5.
6.
7.
private async void Form1_LoadAsync(object sender, EventArgs e)
{
    var t1 = LoadSomeEntities1();
    var t2 = LoadSomeEntities2();
    var t3 = LoadSomeEntities3();
    await Task.WhenAll(t1, t2, t3);
}


Так все три метода будут выполняться одновременно, то есть общее выполнение будет быстрее. Но это если они не обращаются к одним и тем же объектам.


Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
async Task LoadSomeEntities1()
{
    trvTreeView.SuspendLayout();
    trvTreeView.BeginUpdate();
    trvTreeView.Nodes.Clear();

    // Возвращаемся в тот же контекст синхронизации,
    // поэтому вызовы Invoke не нужны.
    await ReadEntitesFromDB();

    foreach (var entity in entities)
    {
        trvTreeView.Nodes.Add(entity.Name);
    }

    trvTreeView.EndUpdate();
    trvTreeView.ResumeLayout();
}


И это всё! Суть и красота асинхронности заключена в лаконичности, которую она позволяет.


Код: c#
1.
2.
3.
4.
private async void ComboBox_SelectedIndexChangedAsync(object sender, EventArgs e)
{
    await LoadSomeEntities3();            
}



Ничего не виснет, всё летает!

ЗЫ: у обработчиков событий в сигнатуре должно быть async.
...
Рейтинг: 0 / 0
08.04.2021, 01:39
    #40060562
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
petalvik
ЗЫ: у обработчиков событий в сигнатуре должно быть async.


да, void async-и поддержали только ради событий WinForms
...
Рейтинг: 0 / 0
08.04.2021, 15:35
    #40060743
От чего может виснуть этот код?
Джон Скит из МС утверждает везде что на каждом асинхронном вызове должен висеть .ConfigureAwait(false).
Вы утверждаете, что это делает вызов синхронным. И кому верить?

> зачем убирать await и добавлять GetResult()? это во-первых неправильно, что как бы подтверждается тем, что "виснет", во-вторых.. зачем? это для чего?

чтобы не висло. Вы, кажется, всё перепутали: как "неправильно" не виснет. Как сейчас виснет.
...
Рейтинг: 0 / 0
08.04.2021, 16:22
    #40060764
От чего может виснуть этот код?
petalvik
Бариску Нацарство,
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
async Task LoadSomeEntities1()
{
    trvTreeView.SuspendLayout();
    trvTreeView.BeginUpdate();
    trvTreeView.Nodes.Clear();

    // Возвращаемся в тот же контекст синхронизации,
    // поэтому вызовы Invoke не нужны.
    await ReadEntitesFromDB();

    foreach (var entity in entities)
    {
        trvTreeView.Nodes.Add(entity.Name);
    }

    trvTreeView.EndUpdate();
    trvTreeView.ResumeLayout();
}


И это всё! Суть и красота асинхронности заключена в лаконичности, которую она позволяет.

ЗЫ: у обработчиков событий в сигнатуре должно быть async.


Сделал всё, как Вы советуете выше. Вроде бы всё работает, только две проблемы остались:

await ReadEntitesFromDB(); виснет, если не добавить .ConfigureAwait(false)

и всё-таки добавление нод в trvTreeView по-прежнему бросает исключение об обращении из другой нити, если не оставить .Invoke((MethodDelegate)
...
Рейтинг: 0 / 0
08.04.2021, 16:37
    #40060773
petalvik
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
Бариску Нацарство,

Вот этот код ошибочен:

Код: c#
1.
2.
3.
4.
5.
6.
private async void Form1_LoadAsync(object sender, EventArgs e)
{
    await LoadSomeEntities1().ConfigureAwait(false);
    await LoadSomeEntities2().ConfigureAwait(false);
    await LoadSomeEntities3().ConfigureAwait(false);
}


Здесь нужно убрать .ConfigureAwait(false). Потому что в этих методах происходит обращение к GUI-контролам.
Правильный код:

Код: c#
1.
2.
3.
4.
5.
6.
private async void Form1_LoadAsync(object sender, EventArgs e)
{
    await LoadSomeEntities1();
    await LoadSomeEntities2();
    await LoadSomeEntities3();
}



Теперь не будет бросать исключение.


Бариску Нацарство

await ReadEntitesFromDB(); виснет, если не добавить .ConfigureAwait(false)

Значит код в методе ReadEntitesFromDB() написан неправильно. Наверняка там тоже присобачено .GetAwaiter().GetResult() или что-то ещё. Покажи код.
...
Рейтинг: 0 / 0
08.04.2021, 16:43
    #40060774
petalvik
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
Бариску Нацарство,

И ещё. Вызовы trvTreeView.SuspendLayout(); и trvTreeView.ResumeLayout(); не нужны. Если, конечно, в тривью не добавляются дочерние контролы вызовом trvTreeView.Controls.Add(...);
...
Рейтинг: 0 / 0
08.04.2021, 23:04
    #40060851
От чего может виснуть этот код?
petalvik
Бариску Нацарство,

Вот этот код ошибочен:


Спасибо, всё почистил, всё работает.
Объяснил бы ещё кто зачем тот самый Джон Скит везде пугает не использовать async void и настаивает чтобы на каждом await висел .ConfigureAwait(false). Я поначалу делал именно как Вы советуете, но меня затроллили и много лет заставляли добавлять .ConfigureAwait(false).
...
Рейтинг: 0 / 0
08.04.2021, 23:19
    #40060857
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
Бариску Нацарство
Объяснил бы ещё кто зачем тот самый Джон Скит везде пугает не использовать async void и настаивает чтобы на каждом await висел .ConfigureAwait(false). Я поначалу делал именно как Вы советуете, но меня затроллили и много лет заставляли добавлять .ConfigureAwait(false).
А не проще ли взять учебник и прочесть, что делает ConfigureAwait(false) и что такое контекст синхронизации и поток пользовательского интерфейса. Не перепечатывать же учебник на форум.
...
Рейтинг: 0 / 0
09.04.2021, 06:38
    #40060877
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
hVostt
да, void async-и поддержали только ради событий WinForms

Почему это? События есть не только в винформс, а много ещё где - в т.ч. в областях, вообще никак не связанных с GUI:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
var timer = new System.Timers.Timer(TimeSpan.FromSeconds(1).TotalMilliseconds)
{
  AutoReset = true,
  Enabled = false
};
timer.Elapsed += TimerElapsed;
timer.Start();
...
static async void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
  await Task.Delay(TimeSpan.FromSeconds(1));
  Console.WriteLine("Tick: {0}", DateTime.Now);
}
...
Рейтинг: 0 / 0
09.04.2021, 09:35
    #40060905
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
ТС ссылку-то не дал, а Джон Скит наверняка имел ввиду - не плодить собственные сигнатуры с async void. А от легаси никуда не денешься, потому это исключение. Да и про ConfugureAwait наверняка указывал те случаи, когда его нельзя применять. Но зачем вникать в детали - давай везде пихать.
...
Рейтинг: 0 / 0
09.04.2021, 10:13
    #40060922
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
Бариску Нацарство
Джон Скит из МС утверждает везде что на каждом асинхронном вызове должен висеть .ConfigureAwait(false).
Вы утверждаете, что это делает вызов синхронным. И кому верить?


ничего он такого не утверждает.
...
Рейтинг: 0 / 0
09.04.2021, 10:14
    #40060923
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
Сон Веры Павловны
Почему это? События есть не только в винформс, а много ещё где - в т.ч. в областях, вообще никак не связанных с GUI:


за пределами WinForms события лучше не использовать.
и вообще забыть про них как про страшный сон.
...
Рейтинг: 0 / 0
09.04.2021, 10:25
    #40060928
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
Shocker.Pro
ТС ссылку-то не дал, а Джон Скит наверняка имел ввиду - не плодить собственные сигнатуры с async void.

Об этом пишет не только Скит (который, кстати говоря, давно уже в гугле работает). Вот, например: https://docs.microsoft.com/en-us/archive/blogs/ptorr/async-exceptions-in-c
Причина достаточно банальна: void не содержит информации о контексте выполнения задачи, т.к. это void. И поэтому с void есть вот такое:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
static async Task Main()
{
  AppDomain.CurrentDomain.UnhandledException += (s, e)
    => Console.WriteLine("UnhandledException: {0}", e.ExceptionObject);
  TaskScheduler.UnobservedTaskException += (s, e) =>
    Console.WriteLine("UnobservedTaskException: {0}", e);
  Console.WriteLine("Running TestTask");
  try
  {
    await TestTask();
  }
  catch (Exception e)
  {
    Console.WriteLine("TestTask error: {0}", e);
  }
  Console.WriteLine("Running TestVoid");
  try
  {
    TestVoid(); // здесь await использовать нельзя
  }
  catch (Exception e)
  {
    Console.WriteLine("TestVoid error: {0}", e);
  }
  Console.WriteLine("done");
}

static async void TestVoid()
{
  await Task.Yield();
  throw new ApplicationException("TestVoid");
}

static async Task TestTask()
{
  await Task.Yield();
  throw new ApplicationException("TestVoid");
}


Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
Running TestTask
TestTask error: System.ApplicationException: TestVoid
   at test2.Program.<TestTask>d__2.MoveNext() in D:\Projects\.Net\_tests\test2\test2\Program.cs:line 54
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at test2.Program.<Main>d__0.MoveNext() in D:\Projects\.Net\_tests\test2\test2\Program.cs:line 26
Running TestVoid
done
UnhandledException: System.ApplicationException: TestVoid
   at test2.Program.<TestVoid>d__1.MoveNext() in D:\Projects\.Net\_tests\test2\test2\Program.cs:line 48
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback,
        Object state, Boolean preserveSyncCtx
)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback,
       Object state, Boolean preserveSyncCtx)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()

Unhandled Exception: System.ApplicationException: TestVoid
   at test2.Program.<TestVoid>d__1.MoveNext() in D:\Projects\.Net\_tests\test2\test2\Program.cs:line 48
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback,
       Object state, Boolean preserveSyncCtx
)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback,
      Object state, Boolean preserveSyncCtx)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
...
Рейтинг: 0 / 0
09.04.2021, 10:31
    #40060931
Сон Веры Павловны
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
hVostt
за пределами WinForms события лучше не использовать.
и вообще забыть про них как про страшный сон.

Интересно, как это можно реализовать, например, в случае SqlConnection.InfoMessage (таких примеров можно привести много)
...
Рейтинг: 0 / 0
09.04.2021, 10:56
    #40060938
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
Сон Веры Павловны
Интересно, как это можно реализовать, например, в случае SqlConnection.InfoMessage (таких примеров можно привести много)


Согласен, есть легаси контракты, которые до сих пор поддерживаются.
От этих эвентов нужно максимально абстрагироваться и декорировать.
...
Рейтинг: 0 / 0
09.04.2021, 14:21
    #40061016
От чего может виснуть этот код?
hVostt
Бариску Нацарство
Джон Скит из МС утверждает везде что на каждом асинхронном вызове должен висеть .ConfigureAwait(false).
Вы утверждаете, что это делает вызов синхронным. И кому верить?


ничего он такого не утверждает.


Он именно так и утверждает в каждом из его 1000ч постов, которые он плодит на стэкэксчендже и в каждом ссылается на свои блог посты. Везде одно и то же: вешайте .ConfigureAwait(false) на каждый await чтобы не было дедлоков.
...
Рейтинг: 0 / 0
09.04.2021, 14:24
    #40061020
От чего может виснуть этот код?
Shocker.Pro
А не проще ли взять учебник и прочесть

А какой учебник?

Я 5 лет работал в компании, где, в соответствии утверждениям Скита, .ConfigureAwait(false) висел на каждом await, и мои пулл реквесты не одобряли, пока я не добавлял их. Объяснить, зачем они это требуют, правда тоже не могли.
...
Рейтинг: 0 / 0
09.04.2021, 14:47
    #40061036
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
Бариску Нацарство
Везде одно и то же: вешайте .ConfigureAwait(false) на каждый await чтобы не было дедлоков.

Блин, а просто самому прочтитать доки о том, что делает .ConfigureAwait(...) сложно, что ли?
...
Рейтинг: 0 / 0
09.04.2021, 17:40
    #40061118
От чего может виснуть этот код?
fkthat
Бариску Нацарство
Везде одно и то же: вешайте .ConfigureAwait(false) на каждый await чтобы не было дедлоков.

Блин, а просто самому прочтитать доки о том, что делает .ConfigureAwait(...) сложно, что ли?


Configures the awaiter to await this Task<TResult>.

true to attempt to marshal the continuation back to the original context captured; otherwise, false.

И что это мне должно сказать?
...
Рейтинг: 0 / 0
09.04.2021, 18:06
    #40061138
felix_ff
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
От чего может виснуть этот код?
...
Рейтинг: 0 / 0
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / От чего может виснуть этот код? / 25 сообщений из 44, страница 1 из 2
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]