Есть сторонний класс TelnetClient. С помощью него я по нажатию кнопки устанавливаю соединение, и подписываюсь на входящие сообщения. По нажатию другой кнопки отправляю команду на чтение удаленного каталога. Исходники стороннего класса доступны, он основан на TPL, и HandleMessageReceived
вызывается не из ГУИ-потока, поэтому я вынужден использовать (Begin)Invoke
TelnetClient tc = null;
private async void buttonLogin_Click(object sender, EventArgs e)
{
tc = new TelnetClient("host", 23, TimeSpan.FromSeconds(3),
new System.Threading.CancellationToken());
tc.MessageReceived += HandleMessageReceived;
await tc.Connect();
await tc.Send("username");
await tc.Send("password");
}
private void HandleMessageReceived(object sender, MessageEventArgs mea)
{
this.BeginInvoke(new Action(() =>
{
textBox1.Text += mea.Message;
}));
}
private async void buttonSend_Click(object sender, EventArgs e)
{
await tc?.Send("dir");
}
Код работает, но плохо:
1) Выполняется излишне долго (несколько минут). Любым нормальным telnet приложением на этом же хосте команда dir
выполняется в разы быстрее (около секунды).
2) Блокирует ГУИ.
Вопросы
1) Почему блокируется ГУИ? Как избежать?
2) С чем может быть связана низкая производительность? Как избежать?
20K вызовов — это очень много. UI просто не успевает принимать ваши сообщения.
Делайте по-другому. Если у вашего TelnetClient
есть API со Stream
'ом (как в TcpClient
'е), используйте его и читайте построчно.
Если нет — буферизуйте строки в HandleMessageReceived
до какого-нибудь приличного размера, и отправляйте в UI-при достижении предела или через какое-то разумное время (не меньше десятой доли секунды).
Если вы случайно пользуетесь Reactive Extension'ами, то это великолепная цель для их применения (управление backpressure):
Observable.FromEventPattern<MessageReceived>(tc, "MessageReceived")
.Select(mea => mea.Message)
.Buffer(TimeSpan.FromSeconds(0.1))
.Where(list => list.Count > 0)
.Select(list => string.Concat(list))
.ObserveOn(mainSynchronizationContext)
.Subscribe(s => textBox1.Text += s);
А если вы в файл писать будете, то тоже так делать? А если при этом потоков много сразу?
"Процесс не может получить..." - придется выучить наизусть ^^
Надо сделать очередь с обрабатывающим ее одним отдельным потоком writer, соблюдающим заданный интервал, чтобы и обновлялось достаточно быстро и GUI не вешался.
И эту архитектуру копировать из проекта в проект. Даже если пока вроде бы и нен адо.
Я ее делаю сам, но можно поискать что-то готовое, выше вот заикнулись про Reactive.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Добрый день, столкнулся с непониманием того как вывести актуальную информацию на TextBox из метода классаУ меня есть класс :
Есть 2 программы1 работает в фоне(далее ФП) другая в оконном режиме(далее ОП)
Как десериализовать ArraySegment в object внутри WebSocke? Я закоментировал часть кода в которой пытался это сделать, к примеру я пытался использовать...
Как у canvas в unity через скрипт получить его дочерний button, чтобы потом иметь возможность обращаться к нему и проверять на нажатия ? Пробовал так: