C# async... await

ВМоисеев

Коллеги, помогите разобраться.Разрабатываю приложения работы с базой данных Oracle.Запросы могут быть долгоиграющими, поэтому на время его выполнения подключаю таймер и отражаю время в прогресс баре.- Ситуация 1: здесь и далее - await wsp.Entity_SP(ИмяХП, sp, asp, ***********);- вызов хранимой процедуры
. . .
 при.tmrStart(); //-- Пуск таймера 
 try { await wsp.Entity_SP(ИмяХП, sp, asp, ***********); }
 catch (System.InvalidOperationException ex) { throw new Exception(ex.Message); }
 catch (Exception ex) {
 при.tmrStop();
 MessageBox.Show(ex.Message, caption_Entity, MessageBoxButton.OK);
 bl_Разрешение = true; //-- Разрешение выполнения функционала компонент
 return;
 }
 при.tmrStop(); //-- Останов таймера
 . . .
======= ПрогрессБар не работает.- Ситуация 2:
. . .
 при.tmrStart(); //-- Пуск таймера 
 await Task.Run(() => wsp.Entity_SP(ИмяХП, sp, asp, ***********));
 if (wsp.wspErr != null) {
 при.tmrStop();
 MessageBox.Show(wsp.wspErr, caption_Entity, MessageBoxButton.OK);
 bl_Разрешение = true; //-- Разрешение выполнения функционала компонент
 return;
 }
 при.tmrStop();
 . . .
======= ПрогрессБар штатно.Дискуссия состоялась здесь
24 ответа

ВМоисеев

ВМоисеев,дружище, ты и сам можешь половину работы сделать.Прогресс не работает когда нет потока.Включаем отладку и идём по шагам по строчкам. Если есть поток, то всё нормально. Если нет, то пишем сюда и смотрим где ты его стартовать должен.Окно потоков: Debug - Window - ...


ВМоисеев

ВМоисеев,ну и можно сделать круче - не включать прогрессбар, пусть хранимка в фоне работает. Сделает - доложит).РазДисаблишь контрол какой нить.


ВМоисеев

await Task.Run(() => wsp.Entity_SP(ИмяХП, sp, asp, ***********));
это что, извините, за лютейший пздц?какой асинк-эвейт здесь? боржоми водкой запивай, чтобы не било по печени!и это ещё что. прогресс бар на выполнение запросов? wat?! мдахх...


ВМоисеев

и это ещё что. прогресс бар
если помнишь, он у него бесконечный туда-сюда).хо-зя́-ин — ба́-рин.


ВМоисеев

>hVostt, сегодня, 20:53 [21046939]>это что, извините, за лютейший пздц?это здесь.>и это ещё что. прогресс бар на выполнение запросов? wat?! мдахх... на слайде, в низу окна, зеленая полоска.


ВМоисеев

на слайде, в низу окна, зеленая полоска.
ну, тогда нормально по дизайну.С остальным то что?Основной вопрос не прогрессе ведь был.


ВМоисеев

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


ВМоисеев

наверное какие-то проблемы с усвоением информации
дипломат))
по какому принципу "зелёная полоска" заполняется? по коду вы не получаете информации о прогрессе.
Иван Иваныч!Бесконечный прогрессбар когда чем ближе к концу тем медленнее.(предположение)


ВМоисеев

>hVostt, сегодня, 20:53 [21046939]>это что, извините, за лютейший пздц?это здесь.>и это ещё что. прогресс бар на выполнение запросов? wat?! мдахх... на слайде, в низу окна, зеленая полоска.
надо прогресс сверху, тогда хорошо показывается :)


ВМоисеев

>hVostt, сегодня, 23:15 [21047202] >никакой работы в вашем таске не выполняется...Вы не правы:
. . .
 //-- Выполнение хранимой процедуры
 public static void Entity_SP(string spname, dlg_sp sp, OracleParameter[] asp, *************** ***********) {
 nRow = 0; //-- Число строк в выборке
 reader = null;
 wspErr = null;

 try {
 using (OracleConnection connection = new OracleConnection(гп.str_Соединение)) {
 connection.Open();
 OracleCommand command = new OracleCommand("", connection);
 command.Parameters.Clear();
 command.Parameters.AddRange(asp);
 command.CommandText = spname;
 command.CommandType = CommandType.StoredProcedure;

 using (reader = (OracleDataReader)command.ExecuteReader()) {
 //-- Формируем коллекцию из выборки
 sp(***********); //-- Обратный вызов
 }
 }
 }
 catch (Exception ex){ wspErr = ex.Message; }
 }
 . . .
>по какому принципу "зелёная полоска" заполняется? по коду вы не получаете информации о прогрессе.Практически определяется некий максимальный интервал выполнения самого длинного запроса для конкретного компьютера сети + гак и эта величина входит а настройки конкретного компа.


ВМоисеев

ВМоисеев,и где же этот код?


ВМоисеев

>ViPRos, сегодня, 23:41 [21047240] >надо прогресс сверху, тогда хорошо показывается :) Спасибо, завтра попробую


ВМоисеев

ViPRos,по тику что ли?


ВМоисеев

ВМоисеев,ээ, ты чего? я первый раз себе позволил пошутитьawait нифига не делает в первом случае


ВМоисеев

да и во втором тожеделай через бакгроундворкер


ВМоисеев

>ViPRos, сегодня, 23:44 [21047245]>и где же этот код? Вы об этом?
//-- Показ ожидания в ProgressBar-е
 private void dpt_Tick(object sender, EventArgs e) {
 iPgbFrm++;
 if (iPgbFrm < 2) return; //-- Ожидание менее 3 секунд ещё комфортно
 if (iPgbFrm == 2) { //-- С 3-ей секунды ожидания покажем ProgressBar
 pgbWin.Visibility = Visibility.Visible;
 pgbWin.Value = iPgbFrm;
 return;
 }
 pgbWin.Value = iPgbFrm % гп.tm_Запрос + 1;
 }
где:pgbWin - ПрогрессБарiPgbFrm - счетчик секундгп.tm_Запрос - максимальная величина


ВМоисеев

ВМоисеев,
if (wk == null)
 {
 wk = new BackgroundWorker();
 wk.WorkerReportsProgress = true;
 wk.WorkerSupportsCancellation = true;

 wk.DoWork += (s, w) =>
 {
 BackgroundWorker sw = s as BackgroundWorker;
 if (Disposing || IsDisposed) sw.CancelAsync();
 else
 {
 if ((onLoad && main.refreshDataOnLoad && !strTreeHasDS) || !onLoad)
 {
 if (isMacro)
 {
 if (main.modelParallelFillMode) main.FillModelParallel(typename, typeid, contextId, macroid, true, !lazyLoading, macroTypeFilters, true, DS, sw);
 else main.FillModelSeq(typename, typeid, contextId, macroid, true, !lazyLoading, macroTypeFilters, true, DS, sw);
 }
 else main.LoadAndFillMacroType(name, contextId, true);
 }
 }

 if (sw.CancellationPending) w.Cancel = true;
 };

 wk.ProgressChanged += (s, w) =>
 {
 if (Disposing || IsDisposed) (s as BackgroundWorker).CancelAsync();
 else
 {
 if ((int)w.UserState == 1) pb.Increment(1);
 else pb.Value = pb.Maximum;
 }
 };

 wk.RunWorkerCompleted += (s, w) =>
 {
 if (w.Cancelled) MessageBox.Show("Возможно не все данные были загружены. Пользователь остановил загрузку данных.");
 if (w.Error != null) MessageBox.Show("Ошибка при загрузке данных - " + w.Error.Message);

 if (!Disposing && !IsDisposed)
 {
 if (DS.Tables[typename].ExtendedProperties.ContainsKey("Where")) DS.Tables[typename].ExtendedProperties["Where"] = baseWhere;

 if (DS.Tables[typename].ExtendedProperties.ContainsKey("WhereFC")) DS.Tables[typename].ExtendedProperties.Remove("WhereFC");

 main.HandleMacroEvents(contextId, "После загрузки");

 if (mainWindowIsTree) fc.FilterString = LCGforFilter.Text == "LCGforFilter" ? "" : LCGforFilter.Text;

 if (main.synchViewWithOwnerMacroType && this.Owner != null && this.Owner is EnterResource && main.IsView(main.GetTypeIDByМаcrоTypeID(macroid))) SynchAfterRefresh();

 if (!main.isolatedDataCacheForMacroType)
 {
 main.loadingCtxs.Remove(contextId);
 if (main.loadingCtxs.Count == 0) main.RaiseListChangedEvents();
 }
 else main.RaiseListChangedEvents(contextId);
 main.RestoreState(dic);

 comboBox1.Enabled = true;
 bindingNavigator1.Enabled = true;
 layoutControl1.Enabled = true;

 notLookup = false;

 loading = false;

 if (findrec != Guid.Empty)
 {
 if (!mainWindowIsTree || asGrid) (gridControl1.DataSource as BindingSource).Position = (gridControl1.DataSource as BindingSource).Find("ИД", findrec);
 else (treeList1.DataSource as BindingSource).Position = (treeList1.DataSource as BindingSource).Find("ИД", findrec);
 }
 else
 {
 if (!mainWindowIsTree || asGrid)
 {
 if (gridControl1.MainView != null) (gridControl1.MainView as ColumnView).MoveFirst();
 }
 else treeList1.MoveFirst();
 }

 if (lazyLoading) ReSetRootRowPosition();
 main.SetChildPositionToFirstRow(this, typename);

 main.LookUpForForm(this, false);

 SetEditMode();

 GantArea();

 pb.Visible = false;

 isBusy = false;
 }
 };
 }
 else
 {
 if (wk.IsBusy)
 {
 while (wk.IsBusy) Application.DoEvents();
 }
 }

 wk.RunWorkerAsync();


ВМоисеев

>ViPRos, сегодня, 23:51 [21047260] >...делай через бакгроундворкер Это уже проходил.Я получил то, что мне надо, но не знаю почему.


ВМоисеев

ВМоисеев,второй вариант просто работает другой поток, потому рисует основной поток


ВМоисеев

>ViPRos, сегодня, 00:00 [21047280]>второй вариант просто работает другой поток, потому рисует основной поток Меня смутило, что это не работает:
var t = Task.Run(() => ShowThreadInfo("Task") );
 t.Wait();


ВМоисеев

>ViPRos, сегодня, 00:00 [21047280]>второй вариант просто работает другой поток, потому рисует основной поток Меня смутило, что это не работает:
var t = Task.Run(() => ShowThreadInfo("Task") );
 t.Wait();
ты же это скопировал отсюда? почему н еработает
using System;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
 public static void Main()
 {
 ShowThreadInfo("Application");

 var t = Task.Run(() => ShowThreadInfo("Task") );
 t.Wait();
 }

 static void ShowThreadInfo(String s)
 {
 Console.WriteLine("{0} Thread ID: {1}",
 s, Thread.CurrentThread.ManagedThreadId);
 }
}
// The example displays the following output:
// Application thread ID: 1
// Task thread ID: 3


ВМоисеев

что бы твой метод был асинхронной и использовать await и т.д. надо что бы он был типа этого!!!TaskCompletionSource!!!
public static Task RunAsync(Action action) 
{ 
 var tcs = new TaskCompletionSource<Object>(); 
 ThreadPool.QueueUserWorkItem(_ => 
 { 
 try 
 { 
 action(); 
 tcs.SetResult(null); 
 } 
 catch(Exception exc) { tcs.SetException(exc); } 
 }); 
 return tcs.Task; 
}


ВМоисеев

вот нашел для тебя хороший учебникНа этот случай предусмотрен класс TaskCompletionSource, позволяющий создать задачу Task, которой вы управляете как марионеткой. Вы можете в любой момент сделать эту задачу успешно завершившейся. Или записать в нее исключение и тем самым сказать, что она завершилась с ошибкой. Рассмотрим пример. Предположим, требуется инкапсулировать показываемый пользователю вопрос в следующем методе: Task GetUserPermission() Вопрос представляет собой написанный вами диалог, в котором у пользователя запрашивается какое-то разрешение. Поскольку запрашивать разрешение нужно в разных местах приложения, важно, чтобы метод было просто вызывать. Идеальная ситуация для использования асинхронного метода, так как мы не хотим, чтобы этот диалог отображался в потоке пользовательского интерфейса. Однако этот метод очень далек от традиционных асинхронных методов, в которых 54 Глава 6. Паттерн TAPпроизводится обращение к сети или еще какая-то длительная операция. В данном случае мы ждем ответа от пользователя. Рассмотрим тело метода. private Task GetUserPermission() { // Создать объект TaskCompletionSource, чтобы можно было вернуть // задачу-марионетку TaskCompletionSource tcs = new TaskCompletionSource(); // Создать диалог PermissionDialog dialog = new PermissionDialog(); // Когда пользователь закроет диалог, сделать задачу завершившейся // с помощью метода SetResult dialog.Closed += delegate { tcs.SetResult(dialog.PermissionGranted); }; // Показать диалог на экране dialog.Show(); // Вернуть еще не завершившуюся задачу-марионетку return tcs.Task; } Обратите внимание, что метод не помечен ключевым словом async; мы создаем объект Task вручную и не нуждаемся в помощи компилятора. TaskCompletionSource создает объект Task и предоставляет к нему доступ через свойство Task. Мы возвращаем этот объект, а позже делаем его завершившимся, вызывая метод SetResult объекта TaskCompletionSource. Поскольку мы следовали паттерну TAP, вызывающая программа может просто ждать разрешения пользователя с помощью await. Код получается весьма элегантным: if (await GetUserPermission()) { .... Вызывает раздражение отсутствие неуниверсальной версии класса TaskCompletionSource. Однако Task – подкласс Task, поэтому его можно использовать всюду, где требуется объект Task. Это в свою очередь означает, что можно воспользоваться классом TaskCompletionSource, и рассматривать объект типа Task, являющийся значением свойства Task, как объект типа Task. Я обычно работаю с конкретизацией TaskCompletionSource и для ее заполнения вызываю SetResult(null). При желании нетрудно создать неуниверсальную версию TaskCompletionSource, основываясь на универсальной


ВМоисеев

Асинхронное программирование в C# 5.0Алекс Дэвис53 страница