finishes: fast millions of events support
This commit is contained in:
parent
72865e7f96
commit
2ec7f26387
@ -2,6 +2,7 @@
|
|||||||
{
|
{
|
||||||
public class ActionQueue
|
public class ActionQueue
|
||||||
{
|
{
|
||||||
|
// Using ConcurrentQueue<> here would make this process slower.
|
||||||
private readonly object queueLock = new object();
|
private readonly object queueLock = new object();
|
||||||
private readonly AutoResetEvent signal = new AutoResetEvent(false);
|
private readonly AutoResetEvent signal = new AutoResetEvent(false);
|
||||||
private List<Action> queue = new List<Action>();
|
private List<Action> queue = new List<Action>();
|
||||||
|
@ -4,6 +4,7 @@ using System;
|
|||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
namespace OverwatchTranscript
|
namespace OverwatchTranscript
|
||||||
{
|
{
|
||||||
@ -28,8 +29,7 @@ namespace OverwatchTranscript
|
|||||||
private readonly OverwatchTranscript model;
|
private readonly OverwatchTranscript model;
|
||||||
private bool closed;
|
private bool closed;
|
||||||
private long momentCounter;
|
private long momentCounter;
|
||||||
private readonly object queueLock = new object();
|
private readonly ConcurrentQueue<OverwatchMoment> queue = new ConcurrentQueue<OverwatchMoment>();
|
||||||
private readonly List<OverwatchMoment> queue = new List<OverwatchMoment>();
|
|
||||||
private readonly Task queueFiller;
|
private readonly Task queueFiller;
|
||||||
|
|
||||||
public TranscriptReader(string workingDir, string inputFilename)
|
public TranscriptReader(string workingDir, string inputFilename)
|
||||||
@ -95,22 +95,36 @@ namespace OverwatchTranscript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly object nextLock = new object();
|
||||||
|
private OverwatchMoment? moment = null;
|
||||||
|
private OverwatchMoment? next = null;
|
||||||
|
|
||||||
public bool Next()
|
public bool Next()
|
||||||
{
|
{
|
||||||
CheckClosed();
|
CheckClosed();
|
||||||
OverwatchMoment moment = null!;
|
|
||||||
OverwatchMoment? next = null;
|
|
||||||
lock (queueLock)
|
|
||||||
{
|
|
||||||
if (queue.Count == 0) return false;
|
|
||||||
moment = queue[0];
|
|
||||||
if (queue.Count > 1) next = queue[1];
|
|
||||||
|
|
||||||
queue.RemoveAt(0);
|
OverwatchMoment? m = null;
|
||||||
|
TimeSpan? duration = null;
|
||||||
|
lock (nextLock)
|
||||||
|
{
|
||||||
|
if (next == null)
|
||||||
|
{
|
||||||
|
if (!queue.TryDequeue(out moment)) return false;
|
||||||
|
queue.TryDequeue(out next);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
moment = next;
|
||||||
|
next = null;
|
||||||
|
queue.TryDequeue(out next);
|
||||||
|
}
|
||||||
|
|
||||||
|
m = moment;
|
||||||
|
duration = GetMomentDuration();
|
||||||
}
|
}
|
||||||
|
|
||||||
var duration = GetMomentDuration(moment, next);
|
|
||||||
ActivateMoment(moment, duration);
|
ActivateMoment(moment, duration);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,25 +158,22 @@ namespace OverwatchTranscript
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock (queueLock)
|
while (queue.Count < 10)
|
||||||
{
|
{
|
||||||
while (queue.Count < 100)
|
var moment = reader.Next();
|
||||||
|
if (moment == null)
|
||||||
{
|
{
|
||||||
var moment = reader.Next();
|
reader.Close();
|
||||||
if (moment == null)
|
return;
|
||||||
{
|
|
||||||
reader.Close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
queue.Add(moment);
|
|
||||||
}
|
}
|
||||||
|
queue.Enqueue(moment);
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread.Sleep(1);
|
Thread.Sleep(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimeSpan? GetMomentDuration(OverwatchMoment moment, OverwatchMoment? next)
|
private TimeSpan? GetMomentDuration()
|
||||||
{
|
{
|
||||||
if (moment == null) return null;
|
if (moment == null) return null;
|
||||||
if (next == null) return null;
|
if (next == null) return null;
|
||||||
|
@ -13,6 +13,7 @@ namespace FrameworkTests.OverwatchTranscript
|
|||||||
private TranscriptWriter writer = null!;
|
private TranscriptWriter writer = null!;
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
[Ignore("Takes about 25 minutes to run.")]
|
||||||
public void MillionsOfEvents()
|
public void MillionsOfEvents()
|
||||||
{
|
{
|
||||||
var workdir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
var workdir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||||
@ -20,17 +21,26 @@ namespace FrameworkTests.OverwatchTranscript
|
|||||||
var log = new FileLog(nameof(MillionsOfEvents));
|
var log = new FileLog(nameof(MillionsOfEvents));
|
||||||
writer = new TranscriptWriter(log, workdir);
|
writer = new TranscriptWriter(log, workdir);
|
||||||
|
|
||||||
var tasks = new List<Task>();
|
Stopwatch.Measure(log, "Generate", () =>
|
||||||
for (var i = 0; i < NumberOfThreads; i++)
|
|
||||||
{
|
{
|
||||||
tasks.Add(RunGeneratorThread());
|
var tasks = new List<Task>();
|
||||||
}
|
for (var i = 0; i < NumberOfThreads; i++)
|
||||||
|
{
|
||||||
|
tasks.Add(RunGeneratorThread());
|
||||||
|
}
|
||||||
|
|
||||||
Task.WaitAll(tasks.ToArray());
|
Task.WaitAll(tasks.ToArray());
|
||||||
|
});
|
||||||
|
|
||||||
writer.Write(TranscriptFilename);
|
Stopwatch.Measure(log, "Write", () =>
|
||||||
|
{
|
||||||
|
writer.Write(TranscriptFilename);
|
||||||
|
});
|
||||||
|
|
||||||
ReadTranscript(workdir);
|
Stopwatch.Measure(log, "Read", () =>
|
||||||
|
{
|
||||||
|
ReadTranscript(workdir);
|
||||||
|
});
|
||||||
|
|
||||||
File.Delete(TranscriptFilename);
|
File.Delete(TranscriptFilename);
|
||||||
}
|
}
|
||||||
@ -66,9 +76,15 @@ namespace FrameworkTests.OverwatchTranscript
|
|||||||
Assert.That(reader.Header.NumberOfEvents, Is.EqualTo(expectedNumberOfEvents));
|
Assert.That(reader.Header.NumberOfEvents, Is.EqualTo(expectedNumberOfEvents));
|
||||||
|
|
||||||
var counter = 0;
|
var counter = 0;
|
||||||
|
var current = DateTime.MinValue;
|
||||||
reader.AddEventHandler<MyEvent>(e =>
|
reader.AddEventHandler<MyEvent>(e =>
|
||||||
{
|
{
|
||||||
counter++;
|
counter++;
|
||||||
|
if (e.Moment.Utc < current)
|
||||||
|
{
|
||||||
|
Assert.Fail("Event has moment BEFORE previous one.");
|
||||||
|
}
|
||||||
|
current = e.Moment.Utc;
|
||||||
});
|
});
|
||||||
|
|
||||||
var run = true;
|
var run = true;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user