// Задача: вызывать Fun и получить "n".
//
// После этого последовательны должны быть вызваны:
//
// Action2 (кроме случаев, когда "n" не делится на 2)
// Action3 (кроме случаев, когда "n" не делится на 3)
// Action4 (кроме случаев, когда "n" не делится на 4)
Задача совершенно практическая. Fun может возвращать список необходимых обновлений, а Action2-Action4 производить эти обновления.
В синхронном варианте это решается так:
var service = new Service();
// Синхронный вариант
{
int n = service.Fun();
if (0 == n%2)
service.Action2();
if (0 == n%3)
service.Action3();
if (0 == n%4)
service.Action4();
Console.WriteLine("Complete");
}
Как видим -- ничего сложного. Можно добавлять сколько угодно Action -- сложность системы от этого не будет возрастать.
А теперь попробуем написать асинхронный вариант. Замечу, что потребность взята не с потолка -- при использовании Windows Phone нет возможности вызова веб-методов синхронно -- только асинхронный вариант. У меня получилось вот что:
var service = new Service();
// Асинхронный вариант 1
{
service.FunCompleted += (sender, eventArgs) =>
{
int n = eventArgs.Argument;
if (0 == n % 2)
{
service.Action2Completed +=
(o, myEventArgs) =>
{
if (0 == n % 3)
{
service.Action3Completed
+= (sender1, args1) =>
{
if (0 == n % 4)
{
service.Action4Completed +=
(o1, eventArgs1) =>
{
Console.WriteLine(
"Complete");
};
service.StartAction4();
}
};
service.StartAction3();
}
else
{
if (0 == n % 4)
{
service.Action4Completed +=
(o1, eventArgs1) =>
{
Console.WriteLine(
"Complete");
};
service.StartAction4();
}
}
};
service.StartAction2();
}
else
{
if (0 == n % 3)
{
service.Action3Completed
+= (o, myEventArgs) =>
{
if (0 == n%4)
{
service.Action4Completed +=
(o1, eventArgs1) =>
{
Console.WriteLine(
"Complete");
};
service.StartAction4();
}
};
service.StartAction3();
}
else
{
if (0 == n % 4)
{
service.Action4Completed +=
(o1, eventArgs1) =>
{
Console.WriteLine(
"Complete");
};
service.StartAction4();
}
}
}
};
service.StartFun();
}
Обратите внимание: сложность нарастает по геометрической прогрессии! Для 3х Action имеем 7 условий. Для 4х их будет в 2 раза больше и так далее...
И, собственно, вопрос. Что делать, если таких вот Action в проекте действительно много? Как быть, как написать? Это ж идиотизм какой-то.
Для удобства привожу упрощенный код полностью:
Скрытый текст
using System;
using System.Threading;
namespace ConsoleApplication17
{
class Program
{
class MyEventArgs : EventArgs
{
public int Argument { get; set; }
}
private class Service
{
public event EventHandler<MyEventArgs> FunCompleted;
public event EventHandler Action2Completed;
public event EventHandler Action3Completed;
public event EventHandler Action4Completed;
public void StartFun()
{
(new Thread(() =>
{
Thread.Sleep(1000);
FunCompleted(this, new MyEventArgs { Argument = DateTime.Now.Second });
})).Start();
}
public void StartAction2()
{
(new Thread(() =>
{
Thread.Sleep(1000);
Action2Completed(this, null);
})).Start();
}
public void StartAction3()
{
(new Thread(() =>
{
Thread.Sleep(1000);
Action3Completed(this, null);
})).Start();
}
public void StartAction4()
{
(new Thread(() =>
{
Thread.Sleep(1000);
Action4Completed(this, null);
})).Start();
}
// Синхронный вариантpublic int Fun()
{
return DateTime.Now.Second;
}
public void Action2()
{
}
public void Action3()
{
}
public void Action4()
{
}
}
static void Main(string[] args)
{
// Задача: вызывать Fun 1 и получить "n".
//
// После этого последовательны должны быть вызваны:
//
// Action2 (кроме случаев, когда "n" не делится на 2)
// Action3 (кроме случаев, когда "n" не делится на 3)
// Action4 (кроме случаев, когда "n" не делится на 4)var service = new Service();
// Синхронный вариант
{
int n = service.Fun();
if (0 == n%2)
service.Action2();
if (0 == n%3)
service.Action3();
if (0 == n%4)
service.Action4();
Console.WriteLine("Complete");
}
// Асинхронный вариант 1
{
service.FunCompleted += (sender, eventArgs) =>
{
int n = eventArgs.Argument;
if (0 == n % 2)
{
service.Action2Completed +=
(o, myEventArgs) =>
{
if (0 == n % 3)
{
service.Action3Completed
+= (sender1, args1) =>
{
if (0 == n % 4)
{
service.Action4Completed +=
(o1, eventArgs1) =>
{
Console.WriteLine(
"Complete");
};
service.StartAction4();
}
};
service.StartAction3();
}
else
{
if (0 == n % 4)
{
service.Action4Completed +=
(o1, eventArgs1) =>
{
Console.WriteLine(
"Complete");
};
service.StartAction4();
}
}
};
service.StartAction2();
}
else
{
if (0 == n % 3)
{
service.Action3Completed
+= (o, myEventArgs) =>
{
if (0 == n%4)
{
service.Action4Completed +=
(o1, eventArgs1) =>
{
Console.WriteLine(
"Complete");
};
service.StartAction4();
}
};
service.StartAction3();
}
else
{
if (0 == n % 4)
{
service.Action4Completed +=
(o1, eventArgs1) =>
{
Console.WriteLine(
"Complete");
};
service.StartAction4();
}
}
}
};
service.StartFun();
}
Console.ReadLine();
}
}
}
Здравствуйте, Аноним, Вы писали:
А>И, собственно, вопрос. Что делать, если таких вот Action в проекте действительно много? Как быть, как написать? Это ж идиотизм какой-то.
Спросите здесь.
Не факт, что их ответ вам подойдет на 100%, но чем черт не шутит.
Re[2]: Лавинообразная сложность асинхронных методов
От:
Аноним
Дата:
09.04.12 21:26
Оценка:
Здравствуйте, Lloyd, Вы писали:
L>Спросите здесь. L>Не факт, что их ответ вам подойдет на 100%, но чем черт не шутит.
А если серьезно? Конечно, подразумевалось что гербалаNemerle не предлагать. Даже не знаю как написать, чтобы этого говна не было. Придумал 2 способа, один другого "краше".
1. Все варианты выбора вынести в специальный метод:
private void StartNext()
{
switch(_currentStep)
{
case 1:
if (0 == 2%_result)
_service.StartAction4();
else
...
break;
case ...
}
}
2. Обернуть методы и события сервиса в обертку. При этом вызов метода StartAction не всегда будет вызывать веб-метод, но в любом случае будет вызывать событие ActionComlete.
Но оба уродские.
Вы бы как сделали?
Re[3]: Лавинообразная сложность асинхронных методов
Здравствуйте, Аноним, Вы писали:
L>>Не факт, что их ответ вам подойдет на 100%, но чем черт не шутит.
А>А если серьезно? Конечно, подразумевалось что гербалаNemerle не предлагать.
Может тогда имеет смысл F# посмотреть. Вроде там был функционал для работы с асинхронностью.
Re[4]: Лавинообразная сложность асинхронных методов
От:
Аноним
Дата:
09.04.12 21:43
Оценка:
Здравствуйте, Lloyd, Вы писали:
L>Может тогда имеет смысл F# посмотреть. Вроде там был функционал для работы с асинхронностью.
К сожалению, можно использовать только C#.
Уже по всякому пробовал -- и Rx пробовал задействовать -- ничего не помогло. Везде получаются эти спагетти.
Мне вот интересно как бы вы сделали. А то всегда боюсь, что мой код попадет к другому человеку и он будет меня высмеивать, увидев эти макароны.
Как вы думаете, какой из двух предложенных мной способов лучше?
Здравствуйте, Аноним, Вы писали:
А> // Задача: вызывать Fun и получить "n". А> // А> // После этого последовательны должны быть вызваны: А> // А> // Action2 (кроме случаев, когда "n" не делится на 2) А> // Action3 (кроме случаев, когда "n" не делится на 3) А> // Action4 (кроме случаев, когда "n" не делится на 4)
А> // Асинхронный вариант 1
Если там всего лишь обновления экрана, может правильней запустить все три действия сразу, и пусть они выполнятся в неопределённой последовательности? Причина-то есть в цепочку выстраивать?
Если допустить, что причина есть... ну можно вот так забабахать:
List<EventHandler> seq = new List<EventHandler>();
EventHandler h = (o, eventArgs) => {
lock(seq) if (seq.Any()) {
var a = seq.First();
seq.RemoveAt(0);
a.Invoke(o, eventArgs);
}
};
service.Action2Completed += h;
service.Action3Completed += h;
service.Action4Completed += h;
service.FunCompleted += (o, eventArgs) => {
int n = (eventArgs as MyEventArgs).Argument;
lock (seq) {
seq.Clear();
if (0 == n % 2)
seq.Add((oo, ea) => service.StartAction2());
if (0 == n % 3)
seq.Add((oo, ea) => service.StartAction3());
if (0 == n % 4)
seq.Add((oo, ea) => service.StartAction4());
h.Invoke(o, eventArgs);
}
};
Здравствуйте, Аноним, Вы писали:
А>Мне вот интересно как бы вы сделали. А то всегда боюсь, что мой код попадет к другому человеку и он будет меня высмеивать, увидев эти макароны.
А>Как вы думаете, какой из двух предложенных мной способов лучше?
К сожалению, не могу ответить. У меня когда какая-нить дилемма возникает, я руками пробую разные варианты и смотрю, что в итоге выходит.
Тут не тот случай — мне не доводилось сталкиваться с большим количеством асинхронного кода и поэтому не владею предметом в достаточной степени, чтобы вам что-то советовать.
Вот ещё чудеса сишарпа. Можно почти не менять код синхронного варианта, и сделать его асинхронным
sealed class MyAsyncDemo : IDisposable
{
IEnumerable<object> MainRoutine(int n)
{
//...if (0 == n % 2)
{
service.Action2Completed += callback;
service.StartAction2();
yield return null;
// в этой точке оказываемся после выполнения Action2, имея её результаты как this.resultArgsif (0 == n % 4)
{
service.Action4Completed += callback;
service.StartAction4();
yield return null;
}
// в этой точке оказываемся после выполнения Action4 - т.е. можно сложную логику с кучей ветвлений
}
if (0 == n % 3)
{
service.Action3Completed += callback;
service.StartAction3();
yield return null;
}
}
public MyAsyncDemo(Service service, int n)
{
this.service = service;
callback = new EventHandler(Hdlr);
state = MainRoutine(n).GetEnumerator();
if (!state.MoveNext())
this.Dispose();
}
public void Dispose()
{
state.Dispose();
}
object sender;
EventArgs resultArgs;
EventHandler callback;
Service service;
IEnumerator<object> state;
void Hdlr(object sender, EventArgs args)
{
this.sender = sender;
this.resultArgs = args;
if (!state.MoveNext())
this.Dispose();
}
}
Вызов просто new MyAsyncDemo(service, n); в обработчике FunCompleted
Но вообще — асинхронность, как известно, не нужна
Забанен с формулировкой "клинический дисидент".
Re[2]: Лавинообразная сложность асинхронных методов
От:
Аноним
Дата:
09.04.12 22:19
Оценка:
Здравствуйте, b-3, Вы писали:
b-3>Если допустить, что причина есть... ну можно вот так забабахать:
Да, 3-й способ. К сожалению, не будет выглядеть так компактно, если веб-методы возвращают различные eventArgs и их нужно по-разному обработать. Но все-таки позволяет избежать лавинообразного нарастания сложности. Хотя и выглядит значительно сложнее синхронного варианта.
b-3>Или отрефакторить код в духе этого паттерна.
Там шаблон для синхронного варианта. Но, если я правильно понял, нечто подобное можно сделать и асинхронно -- это второй вариант, который я описал выше: http://rsdn.ru/forum/dotnet/4695359.aspx?tree=tree
b-3>Или развлечься и сделать кустарный async/await на основе yield return
Есть ли образец как сделать? Точно это облегчит жизнь? Ведь ключевых слов async/await в Windows Phone нет. Task то можно написать, но если обертывать вручную -- то очень сомнительно что будет проще...
b-3>А вообще, постановка задачи странная
Есть требование чтобы процессы выполнялись последовательно. Основная причина -- так красивее отображать информацию пользователю. Теоретически можно и одновременно -- но придется переделывать GUI. Да и неудобно как то говорить, что "не получается сделать последовательно, давайте будем делать одновременно". Вроде не мальчик уже, так что нужно делать как требуется, а не как легче.
Кроме того, все-равно нужно отследить момент, когда все задания выполнены и форму индикации обновления можно закрывать (если задания выполняются в разброс -- добавляется еще и список выполненных/не выполненных + блокировки).
Как видите -- проблема не надумана.
Re[2]: yield return вместо async/await
От:
Аноним
Дата:
09.04.12 22:51
Оценка:
Здравствуйте, b-3, Вы писали:
b-3>Вот ещё чудеса сишарпа. Можно почти не менять код синхронного варианта, и сделать его асинхронным
Идея понятна. Да, лихо. Идея похожа на список, но с синтаксическим сахаром.
Ну а практически вы бы какой способ использовали? Когда требуется максимальная простота.
Просто сейчас не знаю как и написать. Пример то мой упрощен. В реальности нужно предусмотреть и обработку ошибок, и восстановление сессии в случае обрыва, и обработку полученных данных. Все выглядит настолько макаронистым -- что просто руки опускаются. Тарелка с лапшой получается.
Проклял 10 раз Микрософта за то что лишили возможности использовать синхронные методы. Сколько раз говорили: никогда не считайте себя умнее пользователя. Они подумали, что мы будем забывать выносить вызов методов из UI потока и вообще лишили нас возможности вызывать методы в UI потоке. Умные. Но вот что делать в таком случае -- они не подумали...
b-3>Но вообще — асинхронность, как известно, не нужна
Верно, в данном случае она не просто не нужна, но очень сильно усложняет задачу. Но ее заставляют использовать принудительно. Видимо WP7 и Silverlight не рассчитаны для таких сложных UseCase. Там должен быть один максимум 2 Web-метода на все приложение.
Здравствуйте, <Аноним>, Вы писали:
А>Есть такая задача:
А>
А> // Задача: вызывать Fun и получить "n".
А> //
А> // После этого последовательны должны быть вызваны:
А> //
А> // Action2 (кроме случаев, когда "n" не делится на 2)
А> // Action3 (кроме случаев, когда "n" не делится на 3)
А> // Action4 (кроме случаев, когда "n" не делится на 4)
А>
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Lloyd, Вы писали:
L>>Может тогда имеет смысл F# посмотреть. Вроде там был функционал для работы с асинхронностью.
А>К сожалению, можно использовать только C#.
А>Уже по всякому пробовал -- и Rx пробовал задействовать -- ничего не помогло. Везде получаются эти спагетти.
А>Мне вот интересно как бы вы сделали. А то всегда боюсь, что мой код попадет к другому человеку и он будет меня высмеивать, увидев эти макароны.
А>Как вы думаете, какой из двух предложенных мной способов лучше?
А чем Rx не помог? Он же нормально такое будет описывать
from n in service.Fun()
from _2 in Observable.If(n%2 == 0, service.Action2(), Observable.Empty<Unit>())
from _3 in Observable.If(n%3 == 0, service.Action3(), Observable.Empty<Unit>())
from _4 in Observable.If(n%4 == 0, service.Action4(), Observable.Empty<Unit>())
select"Completed";
Здравствуйте, Аноним, Вы писали:
А>А теперь попробуем написать асинхронный вариант. Замечу, что потребность взята не с потолка -- при использовании Windows Phone нет возможности вызова веб-методов синхронно -- только асинхронный вариант. У меня получилось вот что:
Здравствуйте, Аноним, Вы писали:
А>Проклял 10 раз Микрософта за то что лишили возможности использовать синхронные методы. Сколько раз говорили: никогда не считайте себя умнее пользователя. Они подумали, что мы будем забывать выносить вызов методов из UI потока и вообще лишили нас возможности вызывать методы в UI потоке. Умные. Но вот что делать в таком случае -- они не подумали...
Безумно рад, что они так сделали. Орды индусов лишены возможности косячить хотя бы одним из возможных путей косячения. Как я ненавидел эти автостартующие жирные приложения в старых виндах — вздохнул с облегчением после Win7 (там система автоматически понижает приоритет потока, обслуживающего автостартующие приложения при входе в систему). Асинхронность — ещё один шаг в верном направлении. Кто не сумеет освоить state machine — будет обречен
Re[3]: Лавинообразная сложность асинхронных методов
Это было первой мыслью. Не работает в версии 7.1 -- просто зависает.
Re[4]: yield return вместо async/await
От:
Аноним
Дата:
10.04.12 09:05
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:
MD>Безумно рад, что они так сделали. Орды индусов лишены возможности косячить хотя бы одним из возможных путей косячения.
Наивный вы человек. Индусов это меньше всего будет заботить -- они будут писать макароны как в самом первом посте и задумываться ни о чем не будут Это добавило геморрой только правильным людям, для которых писать лапша-код недопустимо (ранее был бы только один асинхронный вызов, теперь множество без надобности -- просто усложнение на ровном месте).
MD>Асинхронность — ещё один шаг в верном направлении.
В данном случае нужен лишь один асинхронный вызов с целью избежать длительной операции в UI-потоке. Запуск каждого метода в отдельном потоке ничего кроме сложности не привносит.
Но таким как вы это очень сложно увидеть. Вам MS будет сцать на голову -- а вы будете говорить "Божия роса".
MD>Кто не сумеет освоить state machine — будет обречен
Нифига -- индус просто будет писать спагетти с чувством выполненного долга. Даже не задумываясь, как говориться.
А зависания формы в WP7 очень легко достичь, работая с локальной базой данных. Так что только усложнили жизнь -- никакого профита абсолютно.
Ну и главное. С таким презрительным отношением к партнерам разработчикам далеко не уедешь. Единственные кто с ними будут работать -- так это те же индусы и будут писать так, что волосы на голове дыбом встанут.
Re[4]: Лавинообразная сложность асинхронных методов
Здравствуйте, gandjustas, Вы писали:
G>В WP7 версия SL не совпадает с десктопными.
Забавно. А как тогда, глядя на страничку с описанием в MSDN, понять, поддерживается ли возможность в Windows Phone?
Re[5]: Лавинообразная сложность асинхронных методов
Здравствуйте, HowardLovekraft, Вы писали:
HL>Здравствуйте, gandjustas, Вы писали:
G>>В WP7 версия SL не совпадает с десктопными. HL>Забавно. А как тогда, глядя на страничку с описанием в MSDN, понять, поддерживается ли возможность в Windows Phone?
По Windows Phone отдельный reference
Re[5]: Лавинообразная сложность асинхронных методов
Здравствуйте, HowardLovekraft, Вы писали:
HL>Здравствуйте, gandjustas, Вы писали:
G>>В WP7 версия SL не совпадает с десктопными. HL>Забавно. А как тогда, глядя на страничку с описанием в MSDN, понять, поддерживается ли возможность в Windows Phone?
Ыконка специальная есть там.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[8]: Лавинообразная сложность асинхронных методов
Здравствуйте, gandjustas, Вы писали:
V>>А если целиком воспроизвести с подпиской на события с сохранением семантики?
G>Для каждого метода надо что-то в этом роде написать:
G>
Можно сделать статически проверяемое (есть метод FromEventPattern без рефлекшена). Но, как вы справедливо заметили -- ничем не лучше предложенного мной варианта №2 здесь http://rsdn.ru/forum/dotnet/4695359.aspx?tree=tree
То есть смысл один: если нужно вызывать -- вызываем метод а по завершению событие Complete, если не нужно вызывать -- просто дергаем событие Complete.
Хотя, возможно, с Rx в таком виде чуть компактнее будет запись. Но с учетом того, что нужно проверить ошибки и восстановить сессию -- вероятно придется выносить логику проверки в отдельный метод -- тогда компактность будет практически идентичной.
Re[3]: Лавинообразная сложность асинхронных методов
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
V>>>А если целиком воспроизвести с подпиской на события с сохранением семантики?
G>>Для каждого метода надо что-то в этом роде написать:
G>>
Только тебе придется такой код писать для каждой последовательности, потому что у тебя проверки внутри коллбеков. А Observable обертка может быть тупо сгенерирована один раз.
Что касается статически проверяемого кода, то у метода FromEventPattern есть перегрузки, где не требуется строковая передача имени.
Re[4]: Лавинообразная сложность асинхронных методов
От:
Аноним
Дата:
10.04.12 11:39
Оценка:
Здравствуйте, vdimas, Вы писали:
V>Не нужно. Этот else уже есть на самом верхнем уровне.
Где на самом верхнем уровне?
Вот это:
service.FunCompleted += (sender, eventArgs) => {
int n = eventArgs.Argument;
if (0 == n%2)
MakeAction2(service, n)(sender, eventArgs);
else if (0 == n%3)
MakeAction3(service, n)(sender, eventArgs);
else if (0 == n%4)
MakeAction4(service, n)(sender, eventArgs);
}
Представьте ситуацию:
Action2 -- должно выполняться.
Action3 -- НЕ должно выполняться (пропускаем).
Action4 -- должно выполняться.
Ваш вариант выполнит Action2, попадет в MakeAction3 и на этом завершиться. А нужно еще выполнить MakeAction4...
Re[5]: Лавинообразная сложность асинхронных методов
Нетипизировано (согласен, возразили), но размер кода будет в итоге такой же, как в некоторых приведенных декомпозициях, например последний вариант здесь: http://www.rsdn.ru/forum/dotnet/4696155.1.aspx
Т.е. смысла нет.
G>Только тебе придется такой код писать для каждой последовательности, потому что у тебя проверки внутри коллбеков. А Observable обертка может быть тупо сгенерирована один раз.
Покажи каким образом, если каждый раз вызываются разные методы и подписка идет к разным событиям?
Одно из возможных решений, которое я бы предложил, если бы речь не шла о ветвлении всего на 3 ветки — это сделать адаптеры для получения одинакового интерфейса под все разные методы и калбэки: { предикат, ф-ия, сигнал }. После этого будет миниатюрный код для запуска этого дела на чем угодно и как угодно даже вручную: в параллель либо последовательно.
Здравствуйте, Аноним, Вы писали:
А>И, собственно, вопрос. Что делать, если таких вот Action в проекте действительно много? Как быть, как написать? Это ж идиотизм какой-то.
Адъ и ужос!
Заведите массив ссылок на эти самые action. Заполняйте его после возврата из Fun(), а потом после возврата из каждой очередной ActionN() берите из массива следующий элемент, пока не кончатся.
Немного обобщая, при асинхронном программировании лучше состояние держать в явном виде, а не размазывать тонким слоем по логике. И иметь где-то централизованный код, который, глядя на текущее состояние и очередное событие, принимает решение, какое действие сделать следующим, и как изменить состояние.
Re[11]: Лавинообразная сложность асинхронных методов
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
V>>>О том и речь... Не катит. G>>Ты о чем?
V>Нетипизировано (согласен, возразили), но размер кода будет в итоге такой же, как в некоторых приведенных декомпозициях, например последний вариант здесь: http://www.rsdn.ru/forum/dotnet/4696155.1.aspx
V>Т.е. смысла нет.
Вообще-то твой код задачу не решает Кроме того у тебя логика дублирована, и частично находится внутри коллбеков.
Небольшое изменение логики и все переписывать. Rx и TPL таким не страдают.
G>>Только тебе придется такой код писать для каждой последовательности, потому что у тебя проверки внутри коллбеков. А Observable обертка может быть тупо сгенерирована один раз. V>Покажи каким образом, если каждый раз вызываются разные методы и подписка идет к разным событиям?
Статически сгенерировать нужные экстеншены. Есть даже такая утилита для событий UI. сове сделать один раз совсем несложно.
Re[12]: Лавинообразная сложность асинхронных методов
От:
Аноним
Дата:
10.04.12 13:57
Оценка:
Здравствуйте, gandjustas, Вы писали: G>Небольшое изменение логики и все переписывать. Rx и TPL таким не страдают.
Абсолютно то же самое без всякого Rx. Что именно Rx упростил? В каком месте?
Зачем тянуть еще и Rx, если абсолютно то же самое можно написать без него??? G>Статически сгенерировать нужные экстеншены. Есть даже такая утилита для событий UI. сове сделать один раз совсем несложно.
Кто такая "сова"?
Re[13]: Лавинообразная сложность асинхронных методов
От:
Аноним
Дата:
10.04.12 14:16
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Абсолютно то же самое без всякого Rx. Что именно Rx упростил? В каком месте? А>Зачем тянуть еще и Rx, если абсолютно то же самое можно написать без него???
Именно об этом я и писал выше: пробовал писать по разному, в т.ч. задействовать Rx -- ничего не помогло избавиться от макарон неоправданной сложности. То есть код перестает быть прозрачным -- в нем легко запутаться и чего-то не увидеть.
Ваш вариант с Rx абсолютно ничем не отличается от приведенного мной варианта с Action. И мой вариант с Action по своей сути ничем не отличается от варианта №2 отсюда: http://rsdn.ru/forum/dotnet/4695359.aspx?tree=tree
(только вместо Action используются обычные методы).
Может вы видите разницу? Кроме того, что кто-то начинает "срать кирпичами" от того, что удалось применить супер модную тезнологию Rx -- какой то еще профит есть???
Принципиальной разницы между ними нет -- сложность та же самая. Получается неоправданно сложно на пустом месте.
Здравствуйте, Аноним, Вы писали:
А>Но таким как вы это очень сложно увидеть. Вам MS будет сцать на голову -- а вы будете говорить "Божия роса".
Ничуть. Например, сокеты в линуксе мне нравятся больше, чем в WinSock (имеется ввиду C без "шарпности"). Вот такая вот "роса".
Более того — это сейчас пишется из-под Линукса (не виртуалка!), на котором бежит RDP с виндой
Re[13]: Лавинообразная сложность асинхронных методов
Здравствуйте, Аноним, Вы писали:
А>И, собственно, вопрос. Что делать, если таких вот Action в проекте действительно много? Как быть, как написать? Это ж идиотизм какой-то.
Я бы использовал F#, и фиг с ним, что FSharp.Core.dll для WP7 весит 930 килобайт. Зато асинхронный код выглядит внешне практически так же, как и синхронный из твоего примера.
Re[14]: Лавинообразная сложность асинхронных методов
Здравствуйте, hardcase, Вы писали:
H>Это вполне нормальная практика, она называется "рукопашное CPS-преобразование". Примерно тоже самое с кодом производит грядущий async/await.
Нет. Версия для C# отличается. У них async/await реализуется не через продолжения как в F#, а через конечный автомат. Есть свои плюсы и минусы. В Немерле тоже сделано по особому.
Re[13]: Лавинообразная сложность асинхронных методов
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, gandjustas, Вы писали:
G>>Небольшое изменение логики и все переписывать. Rx и TPL таким не страдают.
А>Абсолютно то же самое без всякого Rx. Что именно Rx упростил? В каком месте?
В rx очень легко будет записать последовательность операций когда вызов следующей зависит от предыдущей.
А>Зачем тянуть еще и Rx, если абсолютно то же самое можно написать без него???
Тоже самое нельзя — небольшое изменение и вся "красота" рассыпится.
G>>Статически сгенерировать нужные экстеншены. Есть даже такая утилита для событий UI. сове сделать один раз совсем несложно. А>Кто такая "сова"?
Наверное "такое"
Re[2]: Лавинообразная сложность асинхронных методов
L>Не факт, что их ответ вам подойдет на 100%, но чем черт не шутит.
Уж послал так послал
Народная мудрось
всем все никому ничего(с).
Re[14]: Лавинообразная сложность асинхронных методов
От:
Аноним
Дата:
10.04.12 16:47
Оценка:
Здравствуйте, gandjustas, Вы писали:
А>>Зачем тянуть еще и Rx, если абсолютно то же самое можно написать без него??? G>Тоже самое нельзя — небольшое изменение и вся "красота" рассыпится.
Например что? Передать аргументы? Разве сложно?
G>>>Статически сгенерировать нужные экстеншены. Есть даже такая утилита для событий UI. сове сделать один раз совсем несложно. А>>Кто такая "сова"? G>Наверное "такое"
Ну и что такое "сове"? Интересно просто -- совсем не понятен смысл предложения...
Re[6]: yield return вместо async/await
От:
Аноним
Дата:
10.04.12 18:30
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:
MD>Ничуть. Например, сокеты в линуксе мне нравятся больше, чем в WinSock (имеется ввиду C без "шарпности"). Вот такая вот "роса". MD>Более того — это сейчас пишется из-под Линукса (не виртуалка!), на котором бежит RDP с виндой
Тогда приведите аргументы "за" вырезание синхронных методов.
Это удобно лишь для тривиальных случаев. Для сложных случаев такая "помощь" лишь приводит к значительному усложнению.
Ваш аргумент -- мол "индусы увидят и испугаются и уйдут с отрасли" -- как минимум глуп. Напугай ежика голой попой называется... Индусы будут делать лапша-код. И он будет зависать, т.к. наверняка добавят рекурсивные вызовы и оно у них будет периодически зациклиться.
Так что со всех сторон плохо: и добавляет лишнего геммора и от индусов не избавляет.
Re[12]: Лавинообразная сложность асинхронных методов
G>Кроме того у тебя логика дублирована, и частично находится внутри коллбеков.
Я уже напомнил, что всего 3 ветки, чтобы не увлекался рассуждениями в эту область. Как надо делать если однотипных задач будет больше — ответил там же, как раз то место, которое ты скипнул.
G>Небольшое изменение логики и все переписывать. Rx и TPL таким не страдают. G>>>Только тебе придется такой код писать для каждой последовательности, потому что у тебя проверки внутри коллбеков. А Observable обертка может быть тупо сгенерирована один раз. V>>Покажи каким образом, если каждый раз вызываются разные методы и подписка идет к разным событиям? G>Статически сгенерировать нужные экстеншены. Есть даже такая утилита для событий UI. сове сделать один раз совсем несложно.
Здравствуйте, Аноним, Вы писали:
А>Тогда приведите аргументы "за" вырезание синхронных методов. А>Это удобно лишь для тривиальных случаев. Для сложных случаев такая "помощь" лишь приводит к значительному усложнению.
Со временем прихожу к обратному выводу. Синхронный вызов не имеет никаких гарантий максимального времени работы. В тривиальном случае — предсказуемо, но при сложении ряда факторов — взрыв временнОй сложности.
Конкретный пример — Eclipse. Святая в своей простоте идея — показывать юзеру список доступных плагинов и обновлений, далее путём ввода ключевых слов юзер на лету фильтрует всё что надо и тыкает мышкой в галочки, затем жмёт Install. Вписал слово XML — на тебе все XML-плюшки, вписал WTP — показывается Web Tools Platform, ну и так далее. На практике имеем некрасивые тормоза.
Сам по себе список плагинов — летает как надо (видимо, он виртуальный, без запихивания всех строк физически в контрол). Но фильтрация — мамма миа, при большом количестве доступных источников плагинов начинается размышлёж на несколько минут, и это на i7-930 — четыре HT-ядра, т.е. восемь[!] конвейров. Само собой, тут же оказывается, что семь конвейров стоят без дела, а восьмой ушивается в усмерть одним синхронным вызовом (тривиальным, но многоповторным циклом)... UI при этом дохлый, прервать нельзя (точнее, нажатие на ESC будет обработано позднее, сразу по окончании этой мега-фильтрации, разом убивая все результаты поиска). Понятно, что надо бы вынести в поток, и всё такое, но... В общем случае, как программисту угадать, что вызов foo() будет долгоиграющим? Правильно, никак. И тут нам на помощь должен прийти системный API, который автоматически будет подразумевать, что клиенту вернут асинхронный fooStart(), а далее будь добр, дорогой мистер бобр, отметить себе нужный state и ждать нотификации fooEnd().
Кстати, идея слежения за максимальной длительностью вызова — не нова в мобильном мире. Ещё старик Symbian умел удушать любой процесс, главный поток которого жрал более 20 секунд времени. Андроид тоже мониторит загруз CPU, и при повышенных аппетитах приложений может тупо уйти в ребут. Так что, MS тут ничего нового не изобрел.
1. Если есть возможность вынести эту логику в отдельный метод сервиса (этого или другого) тогда все упрощаеться до вызова одного метода и обработки результата.
2. Решение на клиенте в лоб (лучше написать или сгенерировать обертку под каждый метод):
private static AutoResetEvent _resetEvent = new AutoResetEvent(false);
private static void Main(string[] appArgs)
{
// Задача: вызывать Fun 1 и получить "n".
//
// После этого последовательны должны быть вызваны:
//
// Action2 (кроме случаев, когда "n" не делится на 2)
// Action3 (кроме случаев, когда "n" не делится на 3)
// Action4 (кроме случаев, когда "n" не делится на 4)var service = new Service();
// Асинхронный вариант 1var n = -1;
_resetEvent.Reset();
service.FunCompleted += (sender, args) =>
{
n = args.Argument;
_resetEvent.Set();
};
service.StartFun();
_resetEvent.WaitOne();
//или сделав обертку так
n = FunWrapper(service);
//подписка на Completed
service.Action2Completed += Service_ActionCompleted;
service.Action3Completed += Service_ActionCompleted;
service.Action4Completed += Service_ActionCompleted;
if (0 == n % 2)
{
service.StartAction2();
_resetEvent.WaitOne();
}
if (0 == n % 3)
{
service.StartAction3();
_resetEvent.WaitOne();
}
if (0 == n % 4)
{
service.StartAction4();
_resetEvent.WaitOne();
}
Console.WriteLine("Complete");
}
private static void Service_ActionCompleted(object sender, EventArgs e)
{
_resetEvent.Set();
}
private static int FunWrapper(Service service)
{
var resetEvent = new AutoResetEvent(false);
int result = -1;
service.FunCompleted += (sender, args) =>
{
result = args.Argument;
resetEvent.Set();
};
service.StartFun();
resetEvent.WaitOne();
return result;
}
Здравствуйте, Mr.Delphist, Вы писали:
MD>В общем случае, как программисту угадать, что вызов foo() будет долгоиграющим? Правильно, никак.
Не правильно. Для этого нужно иметь голову на плечах.
Вы что предлагаете "на всяких случай" делать исключительно асинхронный вариант для всех методов, которые могут выполняться долго?
Тогда сделайте это для методов:
1. Работы с базой данных -- запросы ведь тоже длительные бывают.
2. Для чтения файла.
3. Да чего уж там -- вообще отменить все синхронные вызовы -- вдруг в каком-то методе длительные вычисления а программист то об этом и не знает...
В том то и соль -- голова на плечах дана для того, чтобы обернуть в асинхронный вызов именно ту операцию, которую требуется.
MD>Кстати, идея слежения за максимальной длительностью вызова — не нова в мобильном мире. Ещё старик Symbian умел удушать любой процесс, главный поток которого жрал более 20 секунд времени. Андроид тоже мониторит загруз CPU, и при повышенных аппетитах приложений может тупо уйти в ребут. Так что, MS тут ничего нового не изобрел.
Пусть следят -- я не против. Закрывают программы, которые тормозят UI-поток или чрезмерно расходуют CPU. Но не нужно усложнять на пустом месте.
Так бы я написал все простым синхронным способом и обернул все в одну асинхронную обертку (чтобы не выполнялось в UI-потоке). А теперь куча дерьма + еще время на переключение потоков тратиться (а это доп. ресурсы, кстати).
Re[2]: Лавинообразная сложность асинхронных методов
От:
Аноним
Дата:
10.04.12 22:13
Оценка:
Здравствуйте, Andrey-D, Вы писали:
AD>2. Решение на клиенте в лоб (лучше написать или сгенерировать обертку под каждый метод):
Это было первой мыслью. Но, к сожалению, не работает -- зависает. Вызов FunCompleted вызывается в UI-потоке, а он заблокирован _resetEvent.WaitOne().
Re[3]: Лавинообразная сложность асинхронных методов
А как ты проверяешь?
На тесте консолька+веб сервис вызов FunCompleted идет в отдельнои потоке.
А>Здравствуйте, Andrey-D, Вы писали:
AD>>2. Решение на клиенте в лоб (лучше написать или сгенерировать обертку под каждый метод):
А>Это было первой мыслью. Но, к сожалению, не работает -- зависает. Вызов FunCompleted вызывается в UI-потоке, а он заблокирован _resetEvent.WaitOne().
Re[13]: Лавинообразная сложность асинхронных методов
G>>Кроме того у тебя логика дублирована, и частично находится внутри коллбеков. V>Я уже напомнил, что всего 3 ветки, чтобы не увлекался рассуждениями в эту область. Как надо делать если однотипных задач будет больше — ответил там же, как раз то место, которое ты скипнул.
Это придется гораздо больше писать.
G>>Небольшое изменение логики и все переписывать. Rx и TPL таким не страдают. G>>>>Только тебе придется такой код писать для каждой последовательности, потому что у тебя проверки внутри коллбеков. А Observable обертка может быть тупо сгенерирована один раз. V>>>Покажи каким образом, если каждый раз вызываются разные методы и подписка идет к разным событиям? G>>Статически сгенерировать нужные экстеншены. Есть даже такая утилита для событий UI. сове сделать один раз совсем несложно. V>Ну так покажи как это будет выглядеть. Любопытно.
Ты быстрее сам примеры в сети найдешь, чем я буду писать.
Если уж очень интересно — подожди.
Re[4]: Лавинообразная сложность асинхронных методов
От:
Аноним
Дата:
10.04.12 22:54
Оценка:
Здравствуйте, Andrey-D, Вы писали:
AD>А как ты проверяешь? AD>На тесте консолька+веб сервис вызов FunCompleted идет в отдельнои потоке.
На эмуляторе Windows Phone7. Там почему то так.
Re[14]: Лавинообразная сложность асинхронных методов
G>>>Кроме того у тебя логика дублирована, и частично находится внутри коллбеков. V>>Я уже напомнил, что всего 3 ветки, чтобы не увлекался рассуждениями в эту область. Как надо делать если однотипных задач будет больше — ответил там же, как раз то место, которое ты скипнул. G>Это придется гораздо больше писать.
А что, есть варианты? Разве есть типизированный способ декларативно привязаться к событию чужого объекта? Проблема примера в том, в том, что асинхронные методы целевого объекта не соответствуют асинхронному паттерну. Т.е. вместо того, чтобы подавать AsyncCallback прямо в вызов метода, приходится подписываться на какое-то мифическое событие. Вот и получил ручную писанину и прочие макароны.
V>>Ну так покажи как это будет выглядеть. Любопытно. G>Ты быстрее сам примеры в сети найдешь, чем я буду писать.
Разве? Мне был интересен момент декларативной подписки на события для заданного примера.
Здравствуйте, Аноним, Вы писали:
А>время на переключение потоков тратиться (а это доп. ресурсы, кстати).
Там, в основном, managed threads в юзерских приложениях — их "переключение" по сути бесплатно
Re[15]: Лавинообразная сложность асинхронных методов
Здравствуйте, vdimas, Вы писали:
V>>>Ну так покажи как это будет выглядеть. Любопытно. G>>Ты быстрее сам примеры в сети найдешь, чем я буду писать.
V>Разве? Мне был интересен момент декларативной подписки на события для заданного примера.
Недекларативно, т.к. задаются императивные операции подписки/отписки. Абсолютно никакой статической проверки — можно ошибиться как указав разные события, к которым подписываемся/отписываемся так и в перечислении типов-аргументов генерика.
К тому же, это просто описание адаптера, который для задачи топикстартера лишь промежуточный. В конечный адаптер надо еще завернуть предикат + вызов метода.
Такая же точно техника и точно так же типы целиком указывать надо.
В общем, эта задача решалась бы банально, если бы не надо было городить такие обертки-адаптеры под нормальный асинхронный паттерн. А чтобы их не надо было городить, надо по исходному WSDL сгенерить код асинхронных вызовов чуть по-другому, чтобы в асинхронный вызов можно было сразу подать AsyncCallback или просто Callback. Тогда на любой из показанных либ или даже вручную это решается проще.
Re[17]: Лавинообразная сложность асинхронных методов
Здравствуйте, vdimas, Вы писали:
V>Такая же точно техника и точно так же типы целиком указывать надо.
V>В общем, эта задача решалась бы банально, если бы не надо было городить такие обертки-адаптеры под нормальный асинхронный паттерн. А чтобы их не надо было городить, надо по исходному WSDL сгенерить код асинхронных вызовов чуть по-другому, чтобы в асинхронный вызов можно было сразу подать AsyncCallback или просто Callback. Тогда на любой из показанных либ или даже вручную это решается проще.
Почему никто не видит самого простого варианта -- оставить синхронные методы. Для сложных ситуаций (цепочки вызовов) так проще и лучше. Забывают, что вызовы бывают не только простыми, но и сложными. Зачем еще что-то городить сверху для сложных ситуаций? KISS -- сделайте это проще, тупорылые.
Программист должен сам решить, в каком случае что использовать. В простейшем случае конечно удобнее асинхронный метод -- когда один вызов и одна подписка. Когда цепочка -- то только синхронные + обертка всех вызовов в асинхронный паттерн. Ну это же очевидно!
Ну ребята, ну нельзя же быть такими тупыми...
Re[18]: Лавинообразная сложность асинхронных методов
Здравствуйте, Аноним, Вы писали:
А>Программист должен сам решить, в каком случае что использовать. В простейшем случае конечно удобнее асинхронный метод -- когда один вызов и одна подписка. Когда цепочка -- то только синхронные + обертка всех вызовов в асинхронный паттерн. Ну это же очевидно!
Это потребует доп. поток. А если у нас много таких процессов паралельно? В общем, не все так просто особенно для мобильного софта, где такты пока считают.
Твоя мысль насчет расписать асинхронный код как синхронный абсолютно правильная и вовсе не новая, но напрямую это не делается, это делается только на продолжениях или их эмуляциях разной степени подробностей, включая фиберы.
Здравствуйте, vdimas, Вы писали:
V>Это потребует доп. поток. А если у нас много таких процессов паралельно? В общем, не все так просто особенно для мобильного софта, где такты пока считают.
Вы не поняли. Сделать возможность использовать синхронные и асинхронные методы -- по выбору.
Для простых случаев -- когда нужно только вызывать метод и получить результат -- использовать асинхронный вариант.
Когда же нужна последовательная сложная комбинация -- только синхронные методы. Чтобы не занимать UI-поток -- всю эту цепочку вызовов запускаем в BackgroundWorker.
Понятно теперь?
V>Твоя мысль насчет расписать асинхронный код как синхронный абсолютно правильная и вовсе не новая, но напрямую это не делается, это делается только на продолжениях или их эмуляциях разной степени подробностей, включая фиберы.
А в каком случае это нужно?
Зачем вообще нужны асинхронные вызовы в WP7? Только для одной цели: не занимать UI-поток. То есть чтобы пользователь вместо замершей формы видел какой-то индикатор прогресса. Тогда достаточно всего 1-го потока дополнительно к UI-потоку. Зачем этой херней усложнением заниматься?
V>Для C# тоже можно построить библиотечно на механизме IEnumerable/yield, разве что fork не получится.
Не в том направлении у вас работают мозги. Для таких случаев как этот -- асинхронные вызовы вообще не нужны (только один BackgroundWorker и все). Ну только геммор и сложность они добавляют и ничего больше.
А эти недоумки из MS таких вещей не понимают. Есть такая болезнь -- усложмизм называется. Когда чел только начал программировать -- хочет сделать все как можно круче -- с применением всех ему известных приемов. И в таком случае дуралей пихает их где можно и где не можна. Так вот именно это произошло с командой Silverlight. Ведь другого никакого логического объяснения нет -- студентов набрали, которые болеют усложмизмом (скорее всего из Индии). И эта их болезнь как раковая опухоль распространяется дальше -- ведь в самом ядре они повставляли палки тем, кто использует принцип KISS.
Мол, раз мы идиоты -- то пусть и другие поймут каково нам, идиотам, страдающим усложмизмом живется...
В новой верссии они в другую крайность перейдут. Как вот Metro -- переболели усложмизмом пользовательского интерфейса -- сделали без всего.
Re[20]: Лавинообразная сложность асинхронных методов
Здравствуйте, Аноним, Вы писали: А>Когда же нужна последовательная сложная комбинация -- только синхронные методы. Чтобы не занимать UI-поток -- всю эту цепочку вызовов запускаем в BackgroundWorker. А>Понятно теперь?
С самого начала было понятно и уже ответил. Это дороже в общем случае. К тому — же неэффективное использование ресурсов ОС.
Если алгоритм многошаговый, то потребуются дополнительные телодвижения по синхронизации шагов алгоритма. Уже многократно показано во всевозможных сценариях, что асинхронная модель и конечный автомат сверху нее (или продолжения) — самый дешевый и масштабируемый подход:
Сравнение масштабируемости синхронного и асинхронного подхода в работе с сетью
V>>Твоя мысль насчет расписать асинхронный код как синхронный абсолютно правильная и вовсе не новая, но напрямую это не делается, это делается только на продолжениях или их эмуляциях разной степени подробностей, включая фиберы. А>А в каком случае это нужно?
Чтобы перейти от описания работы автомата (что есть нетривиально) к "привычному" коду на любимом ЯП.
А>Зачем вообще нужны асинхронные вызовы в WP7? Только для одной цели: не занимать UI-поток. То есть чтобы пользователь вместо замершей формы видел какой-то индикатор прогресса. Тогда достаточно всего 1-го потока дополнительно к UI-потоку. Зачем этой херней усложнением заниматься?
Я уже сказал — тогда появится дополнительная задача общения таких потоков с основным. Тебе придется придумывать калбеки и нотификаторы, привязывать их к примитивам синхронизации и т.д. В конечном итоге ты напишешь точно такую же "асинхронность для бедных", только вручную. Кстате, взять тот же boost::asio, если низлежащая система не предоставляет асинхронных возможностей из коробки, то эта асинхронность эмулируется ручками. Со всеми вытекающими. Предлагаешь каждый раз делать вид, что низлежащая система ничем не может помочь? Можно поинтересоваться — какой смысл? Потому что Not invented here?
Т.е. если эту асинхроность напишешь сам, то тебе будет более понятно происходящее, что ле?
Ну напиши несколько раз, делов-то...
V>>Для C# тоже можно построить библиотечно на механизме IEnumerable/yield, разве что fork не получится. А>Не в том направлении у вас работают мозги. Для таких случаев как этот -- асинхронные вызовы вообще не нужны (только один BackgroundWorker и все). Ну только геммор и сложность они добавляют и ничего больше.
Я не уверен, что приведена задача целиком. Это была выжимка из проблемы. В реальной задаче обычно еще нотификации, ожидания и нетривиальные реакции на результат предыдущих задач. Отличие показаной выжимки от реально-происходящего такое, что в приведенной задаче результат всех предикатов был известен заранее, до вызова первого шага асинхронной операции. А в реальности требуется ветвление по чуть более актуальным признакам.
А>А эти недоумки из MS таких вещей не понимают. Есть такая болезнь -- усложмизм называется. Когда чел только начал программировать -- хочет сделать все как можно круче -- с применением всех ему известных приемов. И в таком случае дуралей пихает их где можно и где не можна. Так вот именно это произошло с командой Silverlight. Ведь другого никакого логического объяснения нет -- студентов набрали, которые болеют усложмизмом (скорее всего из Индии). И эта их болезнь как раковая опухоль распространяется дальше -- ведь в самом ядре они повставляли палки тем, кто использует принцип KISS.
Остапа понесло... Я же говорю — распиши сам ручками несколько вариантов, и ты увидишь, что даже эмулируя асинхронность по предложенному тобой варианту, ты придешь к такому же паттерну асинхронности: { функция, контекст, сигнал_завершения }. И единственный вопрос, на который останется ответить — а нахрена было ручками-то?
А>В новой верссии они в другую крайность перейдут. Как вот Metro -- переболели усложмизмом пользовательского интерфейса -- сделали без всего.
Разве? Поменялось только главное меню оболочки и окантовка окон. ИМХО только для того, чтобы не было столь радикального различия на мобильных платформах с ограниченным разрешением и десктопных. Т.е. они решили сэкономить и не плодить клоны собственных ОС, похоже... Но взять их флагманские продукты: на них риббон, т.е. развитие КЛАССИЧЕСКОГО GUI-меню приложений, и этот риббон никуда не делся и не собирается, а вовсе наоборот — им окучили оставшиеся утилиты, что не окучили при выпуске Win7. Похоже он переживет Metro, которому осталось жить не так долго, согласно прогнозам на развитие разрешающей способности экранов, порядка 7-8 лет. Вернее, само Метро никуда не денется, бо это просто АПИ, но мода на "просто квадратики" в основной теме оформления ес-но пройдет.
Re[3]: Лавинообразная сложность асинхронных методов
От:
Аноним
Дата:
12.04.12 04:33
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Andrey-D, Вы писали:
AD>>2. Решение на клиенте в лоб (лучше написать или сгенерировать обертку под каждый метод):
А>Это было первой мыслью. Но, к сожалению, не работает -- зависает. Вызов FunCompleted вызывается в UI-потоке, а он заблокирован _resetEvent.WaitOne().
Есть рабочее решение для SL связанное с использованием ManualResetEvent.
Для вас все еще актуально?
Re[4]: Лавинообразная сложность асинхронных методов
От:
Аноним
Дата:
12.04.12 20:14
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Есть рабочее решение для SL связанное с использованием ManualResetEvent. А>Для вас все еще актуально?
Для WP7? Актуально конечно.
Re[5]: Лавинообразная сложность асинхронных методов
От:
Аноним
Дата:
13.04.12 04:10
Оценка:
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Аноним, Вы писали:
А>>Есть рабочее решение для SL связанное с использованием ManualResetEvent. А>>Для вас все еще актуально?
А>Для WP7? Актуально конечно.
Для WP7 не пробовал, поэтому ничего не обещаю, но там должен быть точно такой же SL с одним UI-потоком.
Но, в SL та же проблема с цепочками асинхронных вызовов и зависанием главного потока при попытке сделать EventWaitHandle.WaitOne().
Это происходит потому, что мы вызовом WaitOne заставляем ждать главный поток события завершения другого потока, а продолжиться после установки Set он уже не может. Происходит deadlock. На форумах (в том числе англоязычных) рекомендуют не использовать Manual/AutoResetEvent'ы и менять образ мышления на асинхронный. Но разработчики все равно часто задают вопросы о том как избавиться от async лапши в коде.
Проблема с зависанием EventWaitHandle.WaitOne() решается тем, что мы делаем его не в UI-потоке, а в фоновом потоке (с помощью ThreadPool.QueueUserWorkItem, например).
При этом мы не уходим от асинхронности, т.к. нам нужно подписаться на событие завершения кода в фоновом потоке, но при этом вынесенный код можно синхронизировать с помощью сигналов (EventWaitHandle) и имитировать синхронность.
Re[21]: Лавинообразная сложность асинхронных методов
От:
Аноним
Дата:
13.04.12 07:44
Оценка:
Здравствуйте, vdimas, Вы писали:
V>С самого начала было понятно и уже ответил. Это дороже в общем случае. К тому — же неэффективное использование ресурсов ОС.
В конкретном случае -- чем дороже? Требуется последовательное выполнение. Ничего распараллелить нельзя.
Каким образом внесение асинхронных вызовов что-ибо сделает дешевле? Даже если бы был многоядерный процессор -- то не помогло бы, т.к. вызовы последовательные.
V>Чтобы перейти от описания работы автомата (что есть нетривиально) к "привычному" коду на любимом ЯП.
В каком случае вообще нужны асинхронные методы? Только для тривиальных случаев -- подписался на событие и вызвал. Когда комбинация -- то только синхронные методы + обертка в BackgroundWorker.
V>Я уже сказал — тогда появится дополнительная задача общения таких потоков с основным.
А вы BackgroundWorker использовали не? Там это очень просто реализуется.
V> Тебе придется придумывать калбеки и нотификаторы, привязывать их к примитивам синхронизации и т.д.
Бред молодой человек. Курите BackgroundWorker.
Re[22]: Лавинообразная сложность асинхронных методов
Здравствуйте, Аноним, Вы писали:
А>Каким образом внесение асинхронных вызовов что-ибо сделает дешевле? Даже если бы был многоядерный процессор -- то не помогло бы, т.к. вызовы последовательные. А>В каком случае вообще нужны асинхронные методы? Только для тривиальных случаев -- подписался на событие и вызвал. Когда комбинация -- то только синхронные методы + обертка в BackgroundWorker.
Если последовательные операции занимаются вводом/выводом, то асинхронность позволит вообще не занимать поток, пока не завершится очередная операция ввода/вывода. Следовательно, при необходимости этот поток может заниматься другой полезной работой.
Re[5]: Лавинообразная сложность асинхронных методов
Нашел объяснение. В WP7 вызов вебсервисоа осуществляеться в UI потоке, поэтому когда тормозим поток не срабатывает "Completed"
Решаеться запуском в отдельном потоке:
Рабочий пример можно забрать тут (если я правильно понял, что нужно сделать)
Использовал SimpleMvvmToolkit.
А>Здравствуйте, Andrey-D, Вы писали:
AD>>А как ты проверяешь? AD>>На тесте консолька+веб сервис вызов FunCompleted идет в отдельнои потоке.
А>На эмуляторе Windows Phone7. Там почему то так.
Re[6]: Лавинообразная сложность асинхронных методов
А>Здравствуйте, Аноним, Вы писали:
А>>Здравствуйте, Аноним, Вы писали:
А>>>Есть рабочее решение для SL связанное с использованием ManualResetEvent. А>>>Для вас все еще актуально?
А>>Для WP7? Актуально конечно. А>Для WP7 не пробовал, поэтому ничего не обещаю, но там должен быть точно такой же SL с одним UI-потоком.
А>Но, в SL та же проблема с цепочками асинхронных вызовов и зависанием главного потока при попытке сделать EventWaitHandle.WaitOne(). А>Это происходит потому, что мы вызовом WaitOne заставляем ждать главный поток события завершения другого потока, а продолжиться после установки Set он уже не может. Происходит deadlock. На форумах (в том числе англоязычных) рекомендуют не использовать Manual/AutoResetEvent'ы и менять образ мышления на асинхронный. Но разработчики все равно часто задают вопросы о том как избавиться от async лапши в коде.
А>Проблема с зависанием EventWaitHandle.WaitOne() решается тем, что мы делаем его не в UI-потоке, а в фоновом потоке (с помощью ThreadPool.QueueUserWorkItem, например). А>При этом мы не уходим от асинхронности, т.к. нам нужно подписаться на событие завершения кода в фоновом потоке, но при этом вынесенный код можно синхронизировать с помощью сигналов (EventWaitHandle) и имитировать синхронность.
Re[21]: Лавинообразная сложность асинхронных методов
Здравствуйте, vdimas, Вы писали:
А>>В новой верссии они в другую крайность перейдут. Как вот Metro -- переболели усложмизмом пользовательского интерфейса -- сделали без всего.
V>Разве? Поменялось только главное меню оболочки и окантовка окон. ИМХО только для того, чтобы не было столь радикального различия на мобильных платформах с ограниченным разрешением и десктопных. Т.е. они решили сэкономить и не плодить клоны собственных ОС, похоже... Но взять их флагманские продукты: на них риббон, т.е. развитие КЛАССИЧЕСКОГО GUI-меню приложений, и этот риббон никуда не делся и не собирается, а вовсе наоборот — им окучили оставшиеся утилиты, что не окучили при выпуске Win7. Похоже он переживет Metro, которому осталось жить не так долго, согласно прогнозам на развитие разрешающей способности экранов, порядка 7-8 лет. Вернее, само Метро никуда не денется, бо это просто АПИ, но мода на "просто квадратики" в основной теме оформления ес-но пройдет.
Основное отличие метро интерфейса — отсутствие overlapped windows. Того на чем последние 20 лет строился UI. Многим по началу рвет башню. Хочется делать окошки, многоуровневые менюшки, mdi итп
Что касается время жизни metro то совершенно непонятно причем тут разрешение. Ведь в первую очередь все квадратики адаптированы под тач и какое бы разрешение не было размеры планшетов и пальцев мало изменятся.