
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.97.9.175] |
![]() |
|
Сообщ.
#1
,
|
|
|
Есть класс, реализующий функционал Remoting/WCF, в нём метод:
![]() ![]() /// <summary> /// Подать команду серверу /// </summary> /// <param name="sCommand">Сериализованый объект команды</param> /// <returns>Сериализованный ответ</returns> public string SetCommand( string sCommand ) { // поместить команду в очередь ядра MainFormServer.queueFromRemoting.Enqueue ( sCommand ); // File.AppendAllText("log.txt", "Command: " + sCommand + "\n enqueueed\n", // Encoding.GetEncoding(1251)); // Ждать завершения while ( MainFormServer.queueToRemoting.Count == 0 ); // вернуть клиенту ответ return MainFormServer.queueToRemoting.Dequeue ( ); } Что делает, думаю, понятно... В форме работает таймер, который мониторит queueFromRemoting (она public static) и отрабатывает команды. Это проработало в Remoting уже лет 5, всё как часы, идеально. И не на одной машине. Когда я переключился на WCF, метод вызывается (следил по логу - закомментаренная строчка), команда вроде проходит, но в очереди ничего не появляется (делал лог в таймере, длина очереди всегда ==0). При этом сервер виснет, жрёт проц по-полной (50% 2-х голового камня) ![]() ![]() Сервер, естественно, приходится вышибать руками через диспетчер задач. Исключений нигде не вылетает. В чём м.б. причина? Или к статическому объекту нельзя из WCF обращаться? Спасибо. |
Сообщ.
#2
,
|
|
|
Мда ...
Разобрался сам ... Спустя много дней ![]() |
Сообщ.
#3
,
|
|
|
Поделись?
|
Сообщ.
#4
,
|
|
|
Делюсь
![]() Зависон сервера и дикая загрузка проца связана были со строчкой // Ждать завершения while ( MainFormServer.queueToRemoting.Count == 0 ); Таймер формы не видит команду и ничего не делает, в выходной очереди queueToRemoting ничего не появляется, соответственно цикл висит и вешает всё. В такие циклы надо что-то типа Thread.Sleep вставлять, либо таймаут делать, либо вообще менять идеологию опроса очереди. Но это так, мелкие сопутствующие проблемы ... Хоть и неправильно было изначально так делать. Но что сделано, то сделано .... Гораздо большее западло сидело в неверной передаче данных между потоками. WCF - один поток, форма - другой поток. Как только я начал думать в этом направлении, почти сразу же всплыло решение. ![]() ![]() /// <summary> /// Подать команду серверу /// </summary> /// <param name="sCommand">Сериализованый объект команды</param> /// <returns>Сериализованный ответ</returns> public string SetCommand( string sCommand ) { // Проверка объекта команды if ( !CllCntCommand.CanDeserializeDoc ( sCommand ) ) { // ошибка CllCntServerAnswer answ = new CllCntServerAnswer ( -1, "ОШИБКА СЕРВЕРА: Неверная команда" ); answ.text = sCommand; return answ.SerializeStr ( ); } // if return (string)MainFormServer.mForm.Invoke(MainFormServer.mForm.commandDlg, sCommand); } // SetCommand Куски из MainFormServer: В переменных формы ![]() ![]() /// <summary> /// Ссылка на форму /// </summary> public static MainFormServer mForm; /// <summary> /// Тип делегата /// </summary> /// <param name="myString">Команда</param> /// <returns>ОТвет на команду</returns> public delegate string DoCommandDelegate(String myString); /// <summary> /// Делегат для подачи команды /// </summary> public DoCommandDelegate commandDlg; Это статическая ссылка на форму и делегат, обрабатывающий команды клиента. В событии загрузки формы инициализируем добро: ![]() ![]() // Делегат выполнения команд mForm = this; commandDlg = DoCommand; Может можно и в конструкторе, не знаю, не проверял, в загрузке мне кажется надёжнее... Типа объект формы уже полностью инициализирован и пр. Метод обрабатывающий команды: ![]() ![]() private string DoCommand(string sCommand) { return "Ответ на команду "+sCommand; } // DoCommand Таймер и очереди я вообще убрал. Всё равно у меня 100% синхронная отработка команд. Так делать вообще правильнее, хотя я и по сей день не понимаю - почему старый вариант с таймером и очередями как часы работал в Remoting без единого сбоя, а в WCF вообще не работает ![]() Если кто мне объяснит сей "парадокс", буду благодарен. И почему в книгах про WCF даются только примитивные примеры для детского садика типа a+b/c, а действительно сложных вещей с подводными камнями (типа описанных выше) никто нигде не описывает? Нужели все думают, что 100% задач решаемы исключительно в рамках этого одного класса ![]() |
Сообщ.
#5
,
|
|
|
Цитата while ( MainFormServer.queueToRemoting.Count == 0 ); сама по-себе конструкция плохая. Будет много таких потоков, то ресурсов от процессора не останется. лучше использовать [Auto/Manual]ResetEvent. Или колбеки использовать, что лучше всего, в WCF есть такая возможность. Или уж тогда: ![]() ![]() while ( MainFormServer.queueToRemoting.Count == 0 ) { Thread.Sleep(1); } Но ручные слипы потоков - это очень плохо. Старайтесь избегать таких конструкций. Что касается вашего вопроса, то сложно сказать, есть предположение, что каждое обращение к переменной создавался пакет на хост ремотящего объекта MainFormServer, что выглядело примерно так: ![]() ![]() int count = MainFormServer.RequestQueueCount(); while ( count == 0 ) { count = MainFormServer.RequestQueueCount(); } Поскольку RequestQueueCount вызов, то поток не жрал ресурсы, а честно выполнял инструкции и стоял на объектах синхронизации внутри ремотинга. WCF, все-же продвинутей ремотинга, нужно просто посмотреть на ту часть кода и проследить идут ли запросы на ремотящий сервис MainFormServer, для нормальной работы должен быть создан запрос на каждой итерации. Возможно, WCF как-то кеширует значения, т.е. если отправляются 100500 запросов в сек нет смысла слать их все и это значит что поток сожрет ресурсы т.к. кроме цикла он ничего не делает. Надо будет поиграться ![]() |
Сообщ.
#6
,
|
|
|
Спасибо, конечно, но уже всё это увы давно неактуально. Жизнь и судьба увели меня да-алеко от C# и .NET.
А в виде хобби этим заниматься совершенно некогда. PS. Если честно, я даже не знаю, что такое SCRUM ![]() |