C# TCP接受循环的线程类型:BackgroundWorker、线程或线程池
我正在编写一个TCP服务器,它的核心是一段相当标准的bind-listen-accept代码,由C# TCP接受循环的线程类型:BackgroundWorker、线程或线程池,c#,multithreading,tcp,C#,Multithreading,Tcp,我正在编写一个TCP服务器,它的核心是一段相当标准的bind-listen-accept代码,由TcpListener很好地封装。我在开发中运行的代码现在可以工作了,但我希望对我选择的线程模型进行一些讨论: // Set up the socket listener // *THIS* is running on a System.Threading.Thread, of course. tpcListener = new TcpListener(
TcpListener
很好地封装。我在开发中运行的代码现在可以工作了,但我希望对我选择的线程模型进行一些讨论:
// Set up the socket listener
// *THIS* is running on a System.Threading.Thread, of course.
tpcListener = new TcpListener(IPAddress.Any, myPort);
tpcListener.Start();
while (true)
{
Socket so = tpcListener.AcceptSocket();
try
{
MyWorkUnit work = new MyWorkUnit(so);
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(DispatchWork);
bw.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(SendReply);
bw.RunWorkerAsync(work);
}
catch (System.Exception ex)
{
EventLogging.WindowsLog("Error caught: " +
ex.Message, EventLogging.EventType.Error);
}
}
我已经看到了关于选择哪种线程模型(BackgroundWorker、stock thread或ThreadPool)的很好的描述,但没有一个适合这种情况。每种方法的优缺点都有一个很好的总结(第二个答案)。在上面的示例代码中,我选择BackgroundWorker是因为它很简单。是时候弄清楚这是否是正确的方法了
以下是此应用程序的详细信息,它们可能是大多数事务(如TCP服务器)的标准配置:
- 不是Windows窗体应用程序。事实上,它是作为Windows服务运行的
- (我不确定生成的工作是否需要是前台线程。我现在将它们作为后台运行,一切正常。)
- 只要
循环得到周期,分配给线程的任何优先级都可以Accept()
- 我不需要为以后的
或其他任何程序的线程提供固定的IDAbort()
- 线程中运行的任务很短,最多为秒
- 潜在的大量任务可能会很快进入这个循环
- 如果我没有线程,一种“优雅”的拒绝(或排队)新工作的方式会很好
那么,哪种方法才是正确的呢 对于此主线程,使用单独的线程对象。它运行时间长,不太适合线程池(Bgw使用线程池) 在这里,创建它的成本并不重要,而且您(可能)希望完全控制线程的属性 编辑 对于传入请求,您可以使用线程池(直接或通过Bgw),但请注意,这可能会影响吞吐量。当所有线程都忙时,在创建额外线程之前会有一个延迟(0.5秒)。这种线程池行为可能有用,也可能无用。你可以调整MinThreads来控制它 这很粗糙,但是如果你要为衍生的任务创建自己的线程,你可能必须想出自己的节流机制
这完全取决于您期望的请求量,以及请求量的大小 对于此主线程,使用单独的线程对象。它运行时间长,不太适合线程池(Bgw使用线程池) 在这里,创建它的成本并不重要,而且您(可能)希望完全控制线程的属性 编辑 对于传入请求,您可以使用线程池(直接或通过Bgw),但请注意,这可能会影响吞吐量。当所有线程都忙时,在创建额外线程之前会有一个延迟(0.5秒)。这种线程池行为可能有用,也可能无用。你可以调整MinThreads来控制它 这很粗糙,但是如果你要为衍生的任务创建自己的线程,你可能必须想出自己的节流机制
这完全取决于您期望的请求量,以及请求量的大小 对于您的员工来说,BackgroundWorker似乎是一个不错的选择。我唯一需要注意的是,确保您没有阻塞这些线程本身的网络流量。根据需要使用异步方法在那里发送/接收,这样线程池线程就不会因网络流量而被阻塞 这些线程也可以作为后台线程(非常合适)。唯一真正的区别是,在正常情况下,前台线程将使进程保持活动状态
我也不认为你提到了这个抓住这些联系的主线;这是一个适合常规System.Threading.Thread实例的实例。BackgroundWorker对于您的员工来说似乎是一个不错的选择。我唯一需要注意的是,确保您没有阻塞这些线程本身的网络流量。根据需要使用异步方法在那里发送/接收,这样线程池线程就不会因网络流量而被阻塞 这些线程也可以作为后台线程(非常合适)。唯一真正的区别是,在正常情况下,前台线程将使进程保持活动状态
我也不认为你提到了这个抓住这些联系的主线;这一个适合于常规的System.Threading.Thread实例。嗯,就我个人而言,这些都不是我的首选。我倾向于使用
Socket.BeginReceive
和Socket.BeginSend
进行异步IO操作,并让底层IO完成端口为您完成所有线程。但是,如果您更喜欢使用同步IO操作,那么将它们转移到线程池或任务(如果使用.NET 4.0)将是下一个最佳选择。嗯,就我个人而言,这些都不是我的首选。我倾向于使用Socket.BeginReceive
和Socket.BeginSend
进行异步IO操作,并让底层IO完成端口为您完成所有线程。但是,如果您更愿意使用同步IO操作,那么将它们转移到线程池
或任务
(如果使用.NET 4.0)将是次佳选择。是的;任何需要作为独立线程并基本上在应用程序的整个持续时间内运行的任务最终都应该在成熟的线程实例上运行+1但我认为你没有抓住重点。主线程在System.Threading.thread上运行(甚至可能是应用程序的主线程),我将其作为描述添加到代码中。对于衍生出来的任务,我使用什么样的线程;任何需要成为独立线程并基本上运行整个durat的任务