我正在确定是使用TPL数据流模块还是某种生产者/消费者方法进行这些测试。生成任务列表将是非常快的,因为每个任务只是一个字符串,其中包含测试参数列表,例如设置参数,所需的测量以及测量之间的时间。该任务列表将只是通过GUI加载的文件(每个测试1个文件)。
开始测试时,应立即开始。测试可能非常长且非常异步,因为一个操作可能需要几秒钟或数十分钟(例如,加热设备),然后进行一次测量需要几秒钟(或几分钟),然后长时间不进行操作( 24小时),然后再次重复测试。
我最多可以同时运行16个测试,但是我需要能够随时取消任何一个测试的灵活性。我还需要能够随时添加新测试(例如,尝试对16台设备进行测试,或者在一个月中跨月添加和删除各个测试设备的跨度)。
(Visual C#)我尝试了TPL数据流的此示例代码,在该示例代码中,我告诉它同时运行32个简单任务。每个任务仅需5秒的延迟即可模拟工作。由于完成任务所花的时间为15秒,因此似乎正在并行处理任务。我认为由于调度和其他任何开销,所有32个任务都没有在5秒内完成,但是我有点担心某些任务可能被阻止。
class Program
{
// Performs several computations by using dataflow and returns the elapsed
// time required to perform the computations.
static TimeSpan TimeDataflowComputations(int messageCount)
{
// Create an ActionBlock<int> that performs some work.
var workerBlock = new ActionBlock<int>(
// Simulate work by suspending the current thread.
millisecondsTimeout => Thread.Sleep(millisecondsTimeout),
// Specify a maximum degree of parallelism.
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = messageCount
});
// Compute the time that it takes for several messages to
// flow through the dataflow block.
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < messageCount; i++)
{
workerBlock.Post(5000); // simulated work: a delay of 5 seconds.
}
workerBlock.Complete();
// Wait for all messages to propagate through the network.
workerBlock.Completion.Wait();
// Stop the timer and return the elapsed number of milliseconds.
stopwatch.Stop();
return stopwatch.Elapsed;
}
static void Main(string[] args)
{
int messageCount = 32;
TimeSpan elapsed;
// set processors maximum degree of parallelism. This causes
// multiple messages to be processed in parallel.
Console.WriteLine("START:\r\n");
elapsed = TimeDataflowComputations(messageCount);
Console.WriteLine("message count = {1}; " +
"elapsed time = {2}ms.", messageCount,
(int)elapsed.TotalMilliseconds);
Console.ReadLine();
}
}
该演示似乎可以正常运行,但是我不确定在5秒任务中的一项或多项完成之前是否阻止了任何任务。我也不确定如何取消每个动作块以取消特定动作。
答案 0 :(得分:3)
之所以无法获得预期的性能,是因为您的工作负载是同步的,并且阻塞了线程池线程。您是否期望生产环境中实际有同步(阻塞)工作负载?如果是,您可以尝试在启动TPL数据流管道之前提高可用线程的ThreadPool
储备:
ThreadPool.SetMinThreads(workerThreads: 100, completionPortThreads: 100);
如果您的实际工作负载是异步的,那么最好使用Task.Delay
而不是Thread.Sleep
对其进行仿真。
var workerBlock = new ActionBlock<int>(async millisecondsTimeout =>
{
await Task.Delay(millisecondsTimeout);
}, new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = messageCount
});
我没有对其进行测试,但是使用这两种方法,您应该在5秒钟左右获得完成时间。