我正在尝试转换一些代码,只是创建一个新线程来运行一个函数,使其使用一个线程池甚至任务并行库.我这样做是因为我知道尽管工作线程的函数可以无限期地运行(理论上),但每个线程将花费大部分时间无所事事.我还想要一些东西来减少创建和销毁工作线程的开销,因为连接可能会超时或创建新的工作线程.那个 – 并且看到CLRProfiler显示7836个线程在62小时的测试运行之后/之后最终确定有点令人不安,只有一个(如果挑剔的)设备发送消息.
这就是我想要做的事情:
主线程.
1.)让TCPListener接受TcpClient
2.)触发使用该TcpClient的工作线程
3.)如果我们没有被告知停止,请返回步骤1.
工作线程(用于池/任务)
1.)检查我们是否有来自TcpClient的消息
2.)如果是这样,解析消息,发送到数据库,并睡眠1秒钟.
3.)否则,睡眠1毫秒.
4.)如果我们没有被告知停止并且没有超时,请返回步骤1.
这是最初的方法:
private AutoResetEvent connectionWaitHandle = new AutoResetEvent(false); private static bool stop = false; private void MainThread() { TcpListener universalListener = new TcpListener(IPAddress.Any,currentSettings.ListeningPort); universalListener.Start(); while (!stop) { IAsyncResult result = universalListener.BeginAcceptTcpClient(WorkerThread,universalListener); connectionWaitHandle.WaitOne(); connectionWaitHandle.Reset(); } } private void WorkerThread(IAsyncResult result) { TcpListener listener = result.AsyncState as TcpListener; if (listener == null) { connectionWaitHandle.Set(); return; } TcpClient client = listener.EndAcceptTcpClient(result); connectionWaitHandle.Set(); NetworkStream netStream = null; bool timedout = false; try { while (!timedout && !stop) { if (client.Available > 0) { netStream = client.GetStream(); //Get and Parse data here,no need to show this code //The absolute fastest a message can come in is 2 seconds,so we'll sleep for one second so we aren't checking when we don't have to. Thread.Sleep(1000); } else { //Sleep for a millisecond so we don't completely hog the computer's resources. Thread.Sleep(1); } if (/*has timed out*/) { timedout = true; } } } catch (Exception exception) { //Log Exception } finally { client.Close(); } }
我试过替换universalListener.BeginAcceptTcpClient(…)et.全部用
(new Task.TaskFactory.FromAsync<TCPClient>(universalListener.BeginAcceptTcpClient,universalListener.EndAcceptTcpClient,universalListener).ContinueWith(WorkerThread);
以及删除AutoResetEvent connectionWaitHandle代码,但工作线程似乎只触发一次.
我也有点不确定我是否应该尝试使用线程池或任务,因为我可以找到关于线程池和任务(官方文档或其他)的所有内容似乎表明它们应该与具有极端线程的线程一起使用寿命短.
我的问题是:
>线程池或任务并行库中的任务是否适用于长寿命,但主要是车轮旋转,线程?
>如果是这样,我将如何最好地实施正确的模式?
>如果是这样,我是否有正确的想法使用TaskFactory.FromAsync(…).ContinueWith(…)?
解决方法
默认情况下,TPL将使用线程池.因此,无论哪种方式,您都在使用线程池.问题是您使用哪种编程模型来访问池.我强烈建议TPL,因为它提供了一个优秀的编程抽象.
您的示例中的线程实际上没有旋转(燃烧cpu周期),而是在等待句柄上阻塞.这非常有效,并且在被阻止时不消耗线程.
UPDATE
TaskFactory.FromAsync(…).ContinueWith(…)模式是合适的.有很多原因,请参阅this question.
如果您使用的是C#5 / .NET 4.5,则可以使用async / await来更紧凑地表达您的代码模式.