2014-11-26 4 views
0

У меня есть программа для проведения последовательной связи. После отправки команды программе необходимо подождать короткое время, чтобы получить данные. Данные, полученные с помощью ActiveX MSCOMMЗадержка GUI в VB.NET

http://msdn.microsoft.com/en-us/library/aa259393%28v=vs.60%29.aspx

psuedocode выглядит примерно так:

timer_tick

передачи данных (узел 1)

сна (500) «получает данные для узел 1 тем временем

отправить данные (узел 2)

. . .

проблема заключается в том, что сон вызывает отставание графического интерфейса. Я подумал о нескольких альтернативах

1) используя искусственный счетчик в таймере, чтобы приблизиться к 500 мс до отправки следующей команды, но мне не кажется очень хорошей идеей 2) используя поток вместо таймера ? и установить его в качестве фонового потока

http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground(v=vs.71).aspx

3) использование Application.DoEvents?

Мне не знакомы с вариантом 2 или 3, поэтому я не решаюсь ввести в свой код, возможно, усложняющие элементы. Может ли кто-нибудь посоветовать любую альтернативу, которая лучше подходит для этой проблемы или начать работать над вариантом 2 или 3?

+1

Почему бы просто не сделать это в рабочем потоке? –

+0

Хорошо, я на нем! Благодаря! – KRC

+2

Почему вы используете COM-компонент вместо .NET [SerialPort] (http://msdn.microsoft.com/en-us/library/system.io.ports.serialport%28v=vs.110%29.aspx) ? Кроме того, вы ждете, чтобы получить ответ? Было бы хорошо отправить вторую команду раньше, если бы ответ был получен до 500 мс? –

ответ

2

Проблема заключается в том, что ваш timer работает в потоке пользовательского интерфейса, поэтому, когда вы используете sleep в этой подпрограмме, вы спите поток пользовательского интерфейса (отсюда «отставание»).

лучшего вероятно, проще понять вариант заключается в добавлении BackgroundWorker управления в форму и переместить отправки (и спать) код в рабочем DoWork рутину, которая не будет блокировать поток пользовательского интерфейса.

Что-то вроде этого:

Worker_DoWork 
    send data (node 1) 
    sleep(500) 'receives data for node 1 meanwhile 
    send data (node 2) 
End Sub 

Использование DoEvents является сильно расстраивайтесь - есть очень мало причин для использования этого в .NET

+0

Отсутствие оснований для использования BackgroundWorker или Thread.Sleep либо, когда вы можете использовать Tasks и Task.Delay, избегая полной блокировки. –

+0

Не то, что вы думаете. Это не заставляет спать. Он запускает таймер фона, освобождает исходный поток и поднимается после срабатывания таймера. Он не использует и не помещает нить в сон. –

+0

Кроме того, использование задач с 'Async/Await' проще и проще, чем BackgroundWorker во всех случаях. [Стивен Клири] (http://blog.stephencleary.com/2013/05/taskrun-vs-backgroundworker-intro.html) написал исчерпывающую серию сообщений, отображающих все альтернативы тому, что делает BackgroundWorker, и случаи, t, как сообщение о ходе выполнения. –

2

Проблема возникает потому, что вы ставите нить UI спать. В .NET 4.5, вы можете использовать Task.Delay, чтобы сделать код выполнить только по истечении определенного интервала, не блокируя любую тему, например:

Dim port As New SerialPort 
... 
Public Async Sub SomeButton_Click() 
    port.WriteLine("First") 
    Await Task.Delay(500) 
    port.WriteLine("Second") 
    Await Task.Delay(300) 
    port.WriteLine("Third") 
End Sub 

В этом случае первая WriteLine выполняет в потоке пользовательского интерфейса, ожидание происходит в фон на 500 мс (фактически с использованием таймера), затем выполнение возобновляется в исходном потоке (поток пользовательского интерфейса), а второй WriteLine также встречается в потоке пользовательского интерфейса. Еще 300 мс ждут, тогда третья запись также встречается в потоке пользовательского интерфейса.

Комбинация Async\Await позволяет вам написать такой код очень чистым способом, не включая другие компоненты, такие как BackgroundWorker. Он также позволяет делать то, что не может сделать фоновый рабочий, например выполнить несколько асинхронных вызовов. В таком случае вам нужно будет использовать несколько сотрудников, где теперь вы просто напишите еще одно заявление

Обратите внимание, что синтаксис Async Sub используется только для обработчиков событий. Во всех остальных случаях вы должны использовать Async Function SomeFunction() As Task.

Если вы хотите запустить всю последовательность в фоновом потоке, вы можете использовать Task.Run.

Public Async Sub SomeButton_Click() 
    Task.Run(Async Function() 
      Await SendAndWait 
     End Function) 
End Sub 

public Async Function SendAndWait As Task 
    _port.WriteLine("First") 
    Await Task.Delay(500) 
    _port.WriteLine("Second") 
    Await Task.Delay(300) 
    _port.WriteLine("Third") 
End Function 

Реальная красота с помощью задач, является то, что вы можете объединить несколько асинхронных операций, то, что это почти невозможно с BackgroundWorker. В этом случае, вы можете прочитать данные из файла или базы данных асинхронно и отправить его к последовательному порту асинхронно, с очень простой код:

public Async Function SendAndWait(filePath As String) As Task 
    Dim line As String 
     Using reader As New StreamReader(filePath)    
     For i=0 To 3 
      line=Await reader.ReadLineAsync() 
      _port.WriteLine(line) 
      Await Task.Delay(500)     
     Next 
    End Using 
End Function 

Вы можете использовать в async/await ключевые слова в .NET 4.0 код, а также путем добавления пакет Microsoft.Bcl.Async к вашему проекту.

+1

Я не использую .NET 4.5, поэтому я могу использовать только BackgroundWorker. Но спасибо, что предупредил меня о другой альтернативе, если я найду себе работу над последней версией .NET когда-нибудь :) – KRC

+0

Вы также можете использовать все, что в 4.0. Задача была добавлена ​​в .NET 4.0, в то время как пакет [Microsoft.Bcl.Async] (https://www.nuget.org/packages/Microsoft.Bcl.Async) добавляет поддержку для «async/await» до 4.0 для Visual Studio 2012 +. Даже если вы используете VS 2010, вы можете перейти на бесплатную версию Visual Studio 2013 Pro (извините «Сообщество») –

+0

Я использую 1.1 ....><Но большое вам спасибо за вашу полезность! – KRC