我有一個Backgroundworker從UPD設備收集數據。我需要每隔35秒從te設備獲取數據,否則它將被覆蓋。問題是我每+/- 5秒鐘就錯過了一些數據。如果我查看跟蹤中生成的時間戳,我會看到延遲在backgroundworker線程之外。 我通過在需要時刷新Trace日誌和兩個文本編寫器對象來提高性能。c#backgroundworker被.Net任務中斷?
有沒有人知道延遲的原因是什麼?
這裏是我的代碼:
public DataCaptureTabViewModel()
{
SelectDirectoryCommand = new RelayCommand(OnSelectDirectoryCommand);
OpenDirectoryCommand= new RelayCommand(OnOpenDirectoryCommand);
StartStopCaptureCommand = new RelayCommand(OnStartStopCaptureCommand);
var cmdAppl = new GetApplicationSettings();
Mediator.Default.Raise(cmdAppl);
var applicationSettings = cmdAppl.AppSettings;
FilePath = applicationSettings.DefaultPath;
EnableControls = false;
_backgroundWorker = new BackgroundWorker
{
WorkerSupportsCancellation = true,
WorkerReportsProgress = true
};
_backgroundWorker.DoWork += CaptureThread_DoWork;
_backgroundWorker.ProgressChanged += CaptureThread_ProgressChanged;
}
private void CaptureThread_DoWork(object sender, DoWorkEventArgs e)
{
var bgw = (BackgroundWorker)sender;
if (bgw == null) throw new ArgumentException("UpdateBackgroundWorker_DoWork: wrong arguments!");
bgw.ReportProgress(-1, new StringEventArgs(string.Format("Horizontal: {0}/{1} Vertical: {2}/{3} [dropped lines/total]", 0, 0, 0, 0)));
var lastCaptureTime = DateTime.Now;
var lastStatusUpdateTime = DateTime.Now;
var scannedLinesW = 0;
var scannedLinesH = 0;
var droppedLinesW = 0;
var droppedLinesH = 0;
const int nrOfLinesToFlushFileAfter = 500;
uint lastRetrievedBufferTimeStampW = 1;
uint lastRetrievedBufferTimeStampH = 1;
var firstTimeStampW = true;
var firstTimeStampH = true;
TextWriter twW = new StreamWriter(_completeFilePadW, true);
TextWriter twH = new StreamWriter(_completeFilePadH, true);
const string header = "Timestamp; Position;";
var headerW = header;
for (var i = 0; i < NrOfHorizontalBits; i++)
{
headerW += string.Format("b{0};", i);
}
var headerH = header;
for (var i = 0; i < NrOfVerticalBits; i++)
{
headerH += string.Format("b{0};", i);
}
twW.WriteLine(headerW);
twH.WriteLine(headerH);
//send cmd to clear overflow counters and make all buffers invalid
SelectedEmbeddedController.ResetBeamBuffers();
//retrieve sampleTime
var sampleTime = RetrieveSampleTime();
if (sampleTime == 0) sampleTime = 1;
var flushFilesAfterInMs = sampleTime * nrOfLinesToFlushFileAfter;
var lastFlushedTimeW = DateTime.Now;
var lastFlushedTimeH = lastFlushedTimeW.AddMilliseconds((int)(flushFilesAfterInMs/3));
var lastFlushedTraceBuffer = lastFlushedTimeW.AddMilliseconds((int)(flushFilesAfterInMs/3) * 2);
while (!bgw.CancellationPending)
{
//wait, flush in this wait time if needed
var now = DateTime.Now;
if (Helpers.TimeDiffInMs(now, lastFlushedTimeW) > flushFilesAfterInMs)
{
lastFlushedTimeW = DateTime.Now;
twW.Flush();
}
if (Helpers.TimeDiffInMs(now, lastFlushedTimeH) > flushFilesAfterInMs)
{
lastFlushedTimeH = DateTime.Now;
twH.Flush();
}
if (Helpers.TimeDiffInMs(now, lastFlushedTraceBuffer) > flushFilesAfterInMs)
{
lastFlushedTraceBuffer = DateTime.Now;
Trace.Flush();
}
var delay = (int)(MinCaptureTimeInMs - Helpers.TimeDiffInMs(DateTime.Now, lastCaptureTime));
if (delay > 0)
{
Thread.Sleep(delay);
}
//end wait
// capturing data
var startFetch = DateTime.Now;
DebugLogging.WriteLine("*** Fetch all buffers");
const int nrOfRegistersW = (NrOfBuffersUsed * NrOfRegistersPerBufferW);
const int nrOfRegistersH = (NrOfBuffersUsed * NrOfRegistersPerBufferH);
var registersImageW = RetrieveCompleteRegisterBlock(FirstScanRegisterW, nrOfRegistersW);
var registersImageH = RetrieveCompleteRegisterBlock(FirstScanRegisterH, nrOfRegistersH);
DebugLogging.WriteLine("*** Fetch all buffers, ready, FetchTime={0}; timeDiff={1} ms", Helpers.TimeDiffInMs(DateTime.Now, startFetch), Helpers.TimeDiffInMs(DateTime.Now, lastCaptureTime));
lastCaptureTime = DateTime.Now;
/* process Width data */
if (registersImageW == null)
{
DebugLogging.WriteLine("Warning: Width, failed to fetch!");
}
else
{
//first store the received register data into DataStructure List
var dataStructureListW = new List<DataStructure>();
for (var i = 0; i < NrOfBuffersUsed; i++)
{
dataStructureListW.Add(RetrieveDataBuffer(registersImageW, (NrOfRegistersPerBufferW * i), NrOfHorizontalBits));
}
//delete zerro and older datasets
dataStructureListW.RemoveAll(x => x.TimeStampInMs == 0 || x.TimeStampInMs <= lastRetrievedBufferTimeStampW);
//order list by timestamp
var sortedDataStructureListW = dataStructureListW.OrderBy(o => o.TimeStampInMs).ToList();
////delete zerro datasets
//sortedDataStructureListW.RemoveAll(x => x.TimeStampInMs == 0);
////delete older datasets
//sortedDataStructureListW.RemoveAll(x => x.TimeStampInMs <= lastRetrievedBufferTimeStampW);
// parse all horizontal data
var nrOfLinesProcessed = 0;
foreach (var datastructure in sortedDataStructureListW)
{
////first check if timestamp is newer than the last processed buffer
//if (datastructure.TimeStampInMs <= lastRetrievedBufferTimeStampW)
//{
// DebugLogging.WriteLine("Width: Skip buffer, timestamp {0} is same or older then last processed buffer {1}", datastructure.TimeStampInMs, lastRetrievedBufferTimeStampW);
// continue;
//}
int nrOfLinesDiff;
if (firstTimeStampW)
{
nrOfLinesDiff = 1;
firstTimeStampW = false;
}
else
{
nrOfLinesDiff = (int)((datastructure.TimeStampInMs - lastRetrievedBufferTimeStampW)/sampleTime);//how many samples between last fetch and this
var remainder = (datastructure.TimeStampInMs - lastRetrievedBufferTimeStampW) % sampleTime;
if (remainder == (sampleTime - 1))
{
nrOfLinesDiff++;
}
}
if (nrOfLinesDiff > 1)
{
DebugLogging.WriteLine("Width: ## Missed {0} Lines", nrOfLinesDiff - 1);
droppedLinesW += nrOfLinesDiff - 1;
}
//process data
lastRetrievedBufferTimeStampW = datastructure.TimeStampInMs;
//DebugLogging.WriteLine("--- Width: Process buffer with timestamp {0}", datastructure.TimeStampInMs);
//store this data
twW.WriteLine("{0};{1};{2};", datastructure.TimeStampInMs, datastructure.PositionInMs, datastructure.GetDataString());
scannedLinesW++;
nrOfLinesProcessed++;
}
DebugLogging.WriteLine("Width: Processed {0} Lines", nrOfLinesProcessed);
}
/* process Height data */
if (registersImageH == null)
{
DebugLogging.WriteLine("Warning: Height, failed to fetch!");
}
else
{
//first store the received register data into DataStructure List
var dataStructureListH = new List<DataStructure>();
for (var i = 0; i < NrOfBuffersUsed; i++)
{
dataStructureListH.Add(RetrieveDataBuffer(registersImageH, (NrOfRegistersPerBufferH * i), NrOfVerticalBits));
}
//delete zerro and older datasets
dataStructureListH.RemoveAll(x => x.TimeStampInMs == 0 || x.TimeStampInMs <= lastRetrievedBufferTimeStampH);
//order list by timestamp
var sortedDataStructureListH = dataStructureListH.OrderBy(o => o.TimeStampInMs).ToList();
////delete zerro datasets
//sortedDataStructureListH.RemoveAll(x => x.TimeStampInMs == 0);
////delete older datasets
//sortedDataStructureListH.RemoveAll(x => x.TimeStampInMs <= lastRetrievedBufferTimeStampH);
// parse all vertical data
var nrOfLinesProcessed = 0;
foreach (var datastructure in sortedDataStructureListH)
{
////first check if timestamp is newer than the last processed buffer
//if (datastructure.TimeStampInMs <= lastRetrievedBufferTimeStampH)
//{
// DebugLogging.WriteLine("Height: Skip buffer, timestamp {0} is same or older then last processed buffer {1}", datastructure.TimeStampInMs, lastRetrievedBufferTimeStampH);
// continue;
//}
int nrOfLinesDiff;
if (firstTimeStampH)
{
nrOfLinesDiff = 1;
firstTimeStampH = false;
}
else
{
nrOfLinesDiff = (int)((datastructure.TimeStampInMs - lastRetrievedBufferTimeStampH)/sampleTime);//how many samples between last fetch and this
var remainder = (datastructure.TimeStampInMs - lastRetrievedBufferTimeStampH) % sampleTime;
if (remainder == (sampleTime - 1))
{
nrOfLinesDiff++;
}
}
if (nrOfLinesDiff > 1)
{
DebugLogging.WriteLine("Height: ## Missed {0} Lines", nrOfLinesDiff - 1);
droppedLinesH += nrOfLinesDiff - 1;
}
//process data
lastRetrievedBufferTimeStampH = datastructure.TimeStampInMs;
//DebugLogging.WriteLine("--- Height: Process buffer with timestamp {0}", datastructure.TimeStampInMs);
//store this data
twH.WriteLine("{0};{1};{2};", datastructure.TimeStampInMs, datastructure.PositionInMs, datastructure.GetDataString());
scannedLinesH++;
nrOfLinesProcessed++;
}
DebugLogging.WriteLine("Height: Processed {0} Lines", nrOfLinesProcessed);
}
if (Helpers.TimeDiffInMs(DateTime.Now, lastStatusUpdateTime) > StatusUpdateTimeInMs)
{
//send capture status
lastStatusUpdateTime = DateTime.Now;
bgw.ReportProgress(-1,
new StringEventArgs(string.Format("Horizontal: {0}/{1} Vertical: {2}/{3} [dropped lines/total]",
droppedLinesW, scannedLinesW, droppedLinesH, scannedLinesH)));
}
DebugLogging.WriteLine("ProcessTime={0} ms", Helpers.TimeDiffInMs(DateTime.Now, lastCaptureTime));
}
//stop capturing data
twW.Flush();
twW.Close();
twH.Flush();
twH.Close();
}
Normaly獲取數據大約需要7毫秒,但在時間戳10:07:04:833,你可以看到它抽放45毫秒。此延遲不在Backgroundworker線程中。 日誌記錄:
10:07:04:766 *** Fetch all buffers
10:07:04:767 RegistersGet(modbusAddress=02, index=600, size=98)
10:07:04:767 ModbusMsg Send: 06 98 00 00 00 06 02 03 02 58 00 62
10:07:04:769 ModbusMsg Received: 06 98 00 00 00 c6 02 03 00 85 06 b8 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 bd 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 c2 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 c7 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 cc 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 ae 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 b3 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
10:07:04:770 RegistersGet succedded
10:07:04:770 RegistersGet(modbusAddress=02, index=740, size=70)
10:07:04:770 ModbusMsg Send: 06 99 00 00 00 06 02 03 02 e4 00 46
10:07:04:772 ModbusMsg Received: 06 99 00 00 00 8e 02 03 00 85 06 b9 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 be 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 c3 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 c8 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 cd 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 af 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 b4 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff
10:07:04:772 RegistersGet succedded
10:07:04:773 *** Fetch all buffers, ready, FetchTime=7; timeDiff=22 ms
10:07:04:773 Width: Processed 5 Lines
10:07:04:774 Height: Processed 4 Lines
10:07:04:776 ProcessTime=3 ms
10:07:04:788 *** Fetch all buffers
10:07:04:788 RegistersGet(modbusAddress=02, index=600, size=98)
10:07:04:789 ModbusMsg Send: 06 9a 00 00 00 06 02 03 02 58 00 62
10:07:04:810 ModbusMsg Received: 06 9a 00 00 00 c6 02 03 00 85 06 db 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 e0 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 c2 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 c7 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 cc 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 d1 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 d6 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
10:07:04:828 RegistersGet succedded
10:07:04:828 RegistersGet(modbusAddress=02, index=740, size=70)
10:07:04:829 ModbusMsg Send: 06 9b 00 00 00 06 02 03 02 e4 00 46
10:07:04:831 ModbusMsg Received: 06 9b 00 00 00 8e 02 03 00 85 06 ff 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 07 04 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 07 09 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 eb 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 f0 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 f5 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff 00 85 06 fa 00 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff
10:07:04:833 RegistersGet succedded
10:07:04:833 *** Fetch all buffers, ready, FetchTime=45; timeDiff=60 ms
10:07:04:834 Width: Processed 4 Lines
10:07:04:835 Height: ## Missed 5 Lines
10:07:04:836 Height: Processed 7 Lines
你有沒有考慮使用自己的線程(不是BackgroundWorker的),並優先打?這說 - Windows不是一個實時的操作系統,C#不是實時的。 UDP設備不好,因爲它沒有緩衝。你有沒有在那裏檢查API?另類使用高精度回調 - 不是普通的後臺工作者。 – TomTom
我想用Thread來代替,但在互聯網上閱讀告訴我這不會提高性能。我也加了 Thread.CurrentThread.Priority = ThreadPriority.Highest; 到後臺工作,沒有性能增加。 該設備具有緩衝區,並且每35毫秒它們已滿。 我試着製作更多的緩衝區,但後來我需要更多時間來獲取數據。 7個緩衝區具有最佳性能。 – Roy
它只需要一個第2代垃圾收集來破壞你的「實時」保證。不是延遲的唯一來源,您的BGW線程也必須與其他進程擁有的其他線程競爭。 Windows工作站版本上的默認線程量是中斷速率的3倍。 3×15.625〜= 45毫秒。你只能使用timeSetEvent()和一個小心鎖定的機器來使用本機代碼。或者是設備驅動程序。 –