我正在实现一个通过套接字与另一个应用程序A进行通信的库L.
基本工作流程如下:
管理底层数据结构完全没问题。主要的问题是组装“主”任务。当所有(T2)花费大约5-6秒在我的计算机上用大约。 50.000个条目(创建50.000 * 2 + 1个任务)。
然而,我无法想象一个更轻巧的方式来实现同样的目标。它应该使用所有可用的核心并且是非阻塞的,并且支持超时。有没有办法使用Parallel-或ThreadPool类来提高性能?
编辑: 显示基本设置如何的代码: https://dotnetfiddle.net/gIq2DP
答案 0 :(得分:2)
开始总计 n LongRunningTasks
,其中 n 是计算机上的核心数。每个任务都应该在一个核心上运行。为每个要发送的I创建50K新任务将是一种浪费。而是设计接受 I和套接字信息的任务 - 发送此信息的位置。
创建BlockingCollection<Tuple<I, SocketInfo>>
。启动一个任务以填充此阻止集合。您之前创建的其他n个长时间运行的任务可以继续使用信息元组和地址来发送信息,然后在阻塞收集完成时中断的循环中为您执行作业。
可以在长时间运行的任务中设置超时。
这整个设置将使您的CPU忙于有用的工作,而不是让它不必要地忙着“创建 50K任务”的“工作”。
由于发生在主内存之外的操作(如此网络操作)为very very slow,因此可以随意设置 n ,而不仅仅等于机器中的内核数量但即使是三倍的价值。在我的代码演示中,我将其设置为仅等于核心数。
使用所提供链接的代码,这是一种方式......
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Net.NetworkInformation;
using System.Threading.Tasks;
namespace TestConsoleApplication
{
public static class Test
{
public static void Main()
{
TaskRunningTest();
}
private static void TaskRunningTest()
{
var s = new Stopwatch();
const int totalInformationChunks = 50000;
var baseProcessorTaskArray = new Task[Environment.ProcessorCount];
var taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None);
var tcs = new TaskCompletionSource<int>();
var itemsToProcess = new BlockingCollection<Tuple<Information, Address>>(totalInformationChunks);
s.Start();
//Start a new task to populate the "itemsToProcess"
taskFactory.StartNew(() =>
{
// Add Tuples of Information and Address to which this information is to be sent to.
Console.WriteLine("Done intializing all the jobs...");
// Finally signal that you are done by saying..
itemsToProcess.CompleteAdding();
});
//Initializing the base tasks
for (var index = 0; index < baseProcessorTaskArray.Length; index++)
{
var thisIndex = index;
baseProcessorTaskArray[index] = taskFactory.StartNew(() =>
{
while (!itemsToProcess.IsAddingCompleted && itemsToProcess.Count != 0)
{
Tuple<Information, Address> item;
itemsToProcess.TryTake(out item);
//Process the item
tcs.TrySetResult(thisIndex);
}
});
}
// Need to provide new timeout logic now
// Depending upon what you are trying to achieve with timeout, you can devise out the way
// Wait for the base tasks to completely empty OR
// timeout and then stop the stopwatch.
Task.WaitAll(baseProcessorTaskArray);
s.Stop();
Console.WriteLine(s.ElapsedMilliseconds);
}
private class Address
{
//This class should have the socket information
}
private class Information
{
//This class will have the Information to send
}
}
}
答案 1 :(得分:1)
分析表明大多数时间(90%?)花费在计时器设置,到期和处理上。这对我来说似乎有道理。
也许你可以创建自己的超便宜超时机制。将超时排入按到期时间排序的优先级队列。然后,每隔100ms运行一个计时器,并使该计时器到期的优先级队列中的所有内容。
这样做的成本是每个超时一TaskCompletionSource
和一些小的进一步处理。
您甚至可以通过从队列中删除超时来取消超时,只需删除TaskCompletionSource
。