本文介绍了如何获得数据而不会阻塞?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用于获取数据的串行端口外部设备.我设置了两个计时器.其中一个必须用于绘图(0.5sn),另一个必须用于写入文本文件(15sn).计时器不应通过列表或数组相互获取数据.因为有时我需要关闭绘图按钮.

I have a serial port external device for getting data. I set two timers. One of them has to be for plotting(0.5sn) and the other for writing to a text file(15sn). Timers shouldn't get data from each other by list or array. Because sometimes I need to close plotting button.

所以我必须从相同的资源中获取数据(即将获得连续数据),对吗?但是当我尝试此操作时,它被阻止了.

So I have to get data from the same resource (coming continuous data), right? But when I try this, it blocked.

以及如何在不阻塞的情况下获取数据?例如,下面的代码运行时没有阻塞:

And how to get data without blocking?As an example the below code runs without blocking:

# -*- coding: utf-8 -*-
#!/usr/bin/python
import time
import numpy as np
import sys
import wx

def next_data():
    t0 = time.time()
    return t0

class MyFrame1 ( wx.Frame ):

    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 223,183 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )

        self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )

        bSizer1 = wx.BoxSizer( wx.VERTICAL )

        self.toggleBtn1 = wx.ToggleButton( self, wx.ID_ANY, u"Btn 1(enabled)", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer1.Add( self.toggleBtn1, 1, wx.ALL|wx.EXPAND, 5 )

        self.toggleBtn2 = wx.ToggleButton( self, wx.ID_ANY, u"Btn 2(enabled)", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer1.Add( self.toggleBtn2, 1, wx.ALL|wx.EXPAND, 5 )


        self.SetSizer( bSizer1 )
        self.Layout()
        self.timer1 = wx.Timer()
        self.timer1.SetOwner( self, 1 )
        self.timer1.Start( 1000 )

        self.timer2 = wx.Timer()
        self.timer2.SetOwner( self, 2 )
        self.timer2.Start( 1000 )


        self.Centre( wx.BOTH )

        # Connect Events
        self.toggleBtn1.Bind( wx.EVT_TOGGLEBUTTON, self.btn1_f )
        self.toggleBtn2.Bind( wx.EVT_TOGGLEBUTTON, self.btn2_f )
        self.Bind( wx.EVT_TIMER, self.timer1_f, id=1 )
        self.Bind( wx.EVT_TIMER, self.timer2_f, id=2 )

    def btn1_f( self, event ):
        event.Skip()

    def btn2_f( self, event ):
        event.Skip()

    def timer1_f( self, event ):
        t1 = next_data()
        print("t1     :    ",t1)

    def timer2_f( self, event ):
        t2  = next_data()
        print("t2*****:    ",t2)

app = wx.App()
f = MyFrame1(None)
f.Show(True)
app.MainLoop()

它会打印(按预期):

t2*****:     1555568620.1363716
t1     :     1555568620.1363716
t2*****:     1555568621.1300163
t1     :     1555568621.1300163

但是我的串口不能像上面那样正确工作:

However my serial port doesn't work correctly like above:

# -*- coding: utf-8 -*-
#!/usr/bin/python
import time
import numpy as np
import sys
import wx
import serial

ser = serial.Serial('COM9',9600)

def next_data():
    #===========================================================================
    # for line in ser:
    #     return line
    #===========================================================================
    data_str = ser.read(ser.inWaiting())
    return data_str

## also the commented above 2 lines gave same output.


class MyFrame1 ( wx.Frame ):

    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 223,183 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )

        self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )

        bSizer1 = wx.BoxSizer( wx.VERTICAL )

        self.toggleBtn1 = wx.ToggleButton( self, wx.ID_ANY, u"Btn 1(enabled)", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer1.Add( self.toggleBtn1, 1, wx.ALL|wx.EXPAND, 5 )

        self.toggleBtn2 = wx.ToggleButton( self, wx.ID_ANY, u"Btn 2(enabled)", wx.DefaultPosition, wx.DefaultSize, 0 )
        bSizer1.Add( self.toggleBtn2, 1, wx.ALL|wx.EXPAND, 5 )


        self.SetSizer( bSizer1 )
        self.Layout()
        self.timer1 = wx.Timer()
        self.timer1.SetOwner( self, 1 )
        self.timer1.Start( 1000 )

        self.timer2 = wx.Timer()
        self.timer2.SetOwner( self, 2 )
        self.timer2.Start( 1000 )


        self.Centre( wx.BOTH )

        # Connect Events
        self.toggleBtn1.Bind( wx.EVT_TOGGLEBUTTON, self.btn1_f )
        self.toggleBtn2.Bind( wx.EVT_TOGGLEBUTTON, self.btn2_f )
        self.Bind( wx.EVT_TIMER, self.timer1_f, id=1 )
        self.Bind( wx.EVT_TIMER, self.timer2_f, id=2 )

    def btn1_f( self, event ):
        event.Skip()

    def btn2_f( self, event ):
        event.Skip()

    def timer1_f( self, event ):
        t1 = next_data()
        print("t1     :    ",t1)

    def timer2_f( self, event ):
        t2 = next_data()
        print("t2*****:    ",t2)

app = wx.App()
f = MyFrame1(None)
f.Show(True)
app.MainLoop()

及其输出如下:

t2*****:     b'\xb5b\x010\x04\x018\>$GNRMC,063337.00.....$GNGGA...
t1     :     b''
t2*****:     b'\xb5b\x010\x04\x01\x18\>$GNRMC,063338.00.....$GNGGA...
t1     :     b''

和(注释两行):

t2*****:    b'$GPGSV,3,1,11,05,43,248,30,07,31,068,12,08,15,048,23,09,16,128,30*7B\r\n'
t1     :    b'$GPGSV,3,2,11,13,42,311,27,15,10,310,18,17,04,157,09,28,70,161,27*72\r\n'

如所见,t1不获取数据还是t1仅获取下一个数据.我还设置了计时器(100毫秒),但输出相同.有人可以指导我吗,我想念什么?

As seen, whether t1 doesn't get data or t1 just get the next one. I also set timers (100ms), but same output. Could anybody guide me on this, what am I missing?

推荐答案

您不需要 使用2个计时器来定期保存数据.而且您也不需要使用线程.只需在主Frame类(或带有Timer并收集数据的类)中保留一个计数器变量,您的示例就足够简单,可能不需要拆分),然后使用该变量来确定何时写入数据.另外:保持从串行端口读取的数据在同一类的数组中,以便可以对其进行绘制或保存,或者进行其他操作:

You don't need to use 2 Timers to periodically save data. And you do not need to use Threads either. Just keep a counter variable in your main Frame class (or the class with the Timer and collecting the data -- your example is simple enough that it may not need splitting) and use that to determine when to write data. Also: keep the data read from the serial port in an array in the same class so you can plot it or save it or whatever else you might want:

MyFrame1.__init__()添加

self.last_saved_time = 0
self.plotting = True
self.data = []

然后在MyFrame1.timer1()

 # read and save data
 t1 = next_data()
 self.data.append(t1) # (or do more parsing, convert to numpy arrays, etc

 # send to plotting if it is enabled
 if self.plotting:
      self.plot_data()

 # save if needed
 now = time.time()
 if (now - self.last_saved_time) > 15:
      self.save_data_to_file()

同样,您不一定需要两个计时器或线程.您可以在单独的线程中进行绘图或I/O,但是步伐相对较慢.

Again, you do not necessarily need two timers or threads. You could do the plotting or the i/o in a separate thread, but you're going relatively slowly.

最终用自己的事件循环将代码拆分为数据收集器"类,然后将其转移到GUI框架以根据需要进行绘制,可能会更明智.但是这个例子很小,以至于不需要这样的重构.

It would probably be wiser to eventually split up the code as "data collector" class with its own event loop and then transfer that to the GUI frame to plot as needed. But the example is small enough that such a refactoring is not needed yet.

这篇关于如何获得数据而不会阻塞?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-01 19:27