Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум на Исходниках.RU > .NET: Распределенные приложения > Одно и то же работает в Remoting и не работает в WCF |
Автор: hd44780 13.04.12, 10:35 |
Есть класс, реализующий функционал Remoting/WCF, в нём метод: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> /// <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 обращаться? Спасибо. |
Автор: hd44780 03.08.12, 08:52 |
Мда ... Разобрался сам ... Спустя много дней . |
Автор: Mr.Delphist 14.08.12, 09:35 |
Поделись? |
Автор: hd44780 14.08.12, 10:49 |
Делюсь . Зависон сервера и дикая загрузка проца связана были со строчкой // Ждать завершения while ( MainFormServer.queueToRemoting.Count == 0 ); Таймер формы не видит команду и ничего не делает, в выходной очереди queueToRemoting ничего не появляется, соответственно цикл висит и вешает всё. В такие циклы надо что-то типа Thread.Sleep вставлять, либо таймаут делать, либо вообще менять идеологию опроса очереди. Но это так, мелкие сопутствующие проблемы ... Хоть и неправильно было изначально так делать. Но что сделано, то сделано .... Гораздо большее западло сидело в неверной передаче данных между потоками. WCF - один поток, форма - другой поток. Как только я начал думать в этом направлении, почти сразу же всплыло решение. <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> /// <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: В переменных формы <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> /// <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; Это статическая ссылка на форму и делегат, обрабатывающий команды клиента. В событии загрузки формы инициализируем добро: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> // Делегат выполнения команд mForm = this; commandDlg = DoCommand; Может можно и в конструкторе, не знаю, не проверял, в загрузке мне кажется надёжнее... Типа объект формы уже полностью инициализирован и пр. Метод обрабатывающий команды: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> private string DoCommand(string sCommand) { return "Ответ на команду "+sCommand; } // DoCommand Таймер и очереди я вообще убрал. Всё равно у меня 100% синхронная отработка команд. Так делать вообще правильнее, хотя я и по сей день не понимаю - почему старый вариант с таймером и очередями как часы работал в Remoting без единого сбоя, а в WCF вообще не работает . Если кто мне объяснит сей "парадокс", буду благодарен. И почему в книгах про WCF даются только примитивные примеры для детского садика типа a+b/c, а действительно сложных вещей с подводными камнями (типа описанных выше) никто нигде не описывает? Нужели все думают, что 100% задач решаемы исключительно в рамках этого одного класса примитивными методами вроде a+b/c? |
Автор: maxim84_ 14.08.12, 15:04 |
Цитата while ( MainFormServer.queueToRemoting.Count == 0 ); сама по-себе конструкция плохая. Будет много таких потоков, то ресурсов от процессора не останется. лучше использовать [Auto/Manual]ResetEvent. Или колбеки использовать, что лучше всего, в WCF есть такая возможность. Или уж тогда: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> while ( MainFormServer.queueToRemoting.Count == 0 ) { Thread.Sleep(1); } Но ручные слипы потоков - это очень плохо. Старайтесь избегать таких конструкций. Что касается вашего вопроса, то сложно сказать, есть предположение, что каждое обращение к переменной создавался пакет на хост ремотящего объекта MainFormServer, что выглядело примерно так: <{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}> int count = MainFormServer.RequestQueueCount(); while ( count == 0 ) { count = MainFormServer.RequestQueueCount(); } Поскольку RequestQueueCount вызов, то поток не жрал ресурсы, а честно выполнял инструкции и стоял на объектах синхронизации внутри ремотинга. WCF, все-же продвинутей ремотинга, нужно просто посмотреть на ту часть кода и проследить идут ли запросы на ремотящий сервис MainFormServer, для нормальной работы должен быть создан запрос на каждой итерации. Возможно, WCF как-то кеширует значения, т.е. если отправляются 100500 запросов в сек нет смысла слать их все и это значит что поток сожрет ресурсы т.к. кроме цикла он ничего не делает. Надо будет поиграться |
Автор: hd44780 08.07.14, 09:39 |
Спасибо, конечно, но уже всё это увы давно неактуально. Жизнь и судьба увели меня да-алеко от C# и .NET. А в виде хобби этим заниматься совершенно некогда. PS. Если честно, я даже не знаю, что такое SCRUM ... |