C# 执行多个线程的最有效方法 您可以跳过此部分:
我正在创建一个应用程序,客户机需要在其中找到同一网络上的服务器 服务器: 公共静态侦听(Int32端口) { } 假设服务器正在侦听端口12345 然后客户端:C# 执行多个线程的最有效方法 您可以跳过此部分:,c#,multithreading,performance,threadpool,C#,Multithreading,Performance,Threadpool,我正在创建一个应用程序,客户机需要在其中找到同一网络上的服务器 服务器: 公共静态侦听(Int32端口) { } 假设服务器正在侦听端口12345 然后客户端: 获取客户端的当前ip地址,假设它是192.168.5.88 创建所有可能ip地址的列表。如果服务器ip地址与客户端ip地址位于同一本地网络上,则它们可能与客户端ip地址相关,因此我将列表构造为: 192.168.5.0 192.168.5.1 192.168.5.2 192.168.5.3 .....et
- 获取客户端的当前ip地址,假设它是192.168.5.88
- 创建所有可能ip地址的列表。如果服务器ip地址与客户端ip地址位于同一本地网络上,则它们可能与客户端ip地址相关,因此我将列表构造为:
192.168.5.0 192.168.5.1 192.168.5.2 192.168.5.3 .....etc ..... 192.168.0.88 192.168.1.88 192.168.2.88 192.168.3.88 ...etc 192.0.5.88 192.1.5.88 192.2.5.88 192.3.5.88 192.4.5.88 ..... etc 0.168.5.88 1.168.5.88 2.168.5.88 3.168.5.88 4.168.5.88 .... etc
现在我的问题是: 现在我用两种方法来做这件事。我只知道线程的基本知识,我不知道这是否危险,但它的工作速度非常快
// first way
foreach (var ip in ListOfIps)
{
new Thread(new ThreadStart(() =>
{
TryConnect(ip);
})).Start();
}
第二种方式我相信它更安全,但它需要更多的时间:
// second way
foreach (var ip in ListOfIps)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(TryConnect), ip);
}
我必须调用TryConnect方法大约1000次,每次大约需要2秒(我将连接超时设置为2秒)。什么是最有效、最安全的1000次呼叫方式
编辑2 以下是使用不同技术的结果: 1)使用线程池 花了37秒完成 2)使用线程: 花了12秒完成 3)使用任务:
花了8秒在这种情况下,我更喜欢使用线程池线程的解决方案,因为创建1000个线程是一项繁重的操作(考虑到每个线程获得的内存)。 但是自从.NET4以来,还有另一种解决方案,它使用类
Task
。
任务是可以并行执行的工作负载。您可以这样定义和运行它们:
var t = Task.Factory.StartNew(() => DoAction());
您不必关心使用的线程数,因为运行时环境会处理这个问题。因此,如果您有可能将工作负载分成更小的包,这些包可以并行执行,我将使用任务来完成这项工作。在这种情况下,我更喜欢使用线程池线程的解决方案,因为创建1000个线程是一项繁重的操作(考虑到每个线程获得的内存)。 但是自从.NET4以来,还有另一种解决方案,它使用类
Task
。
任务是可以并行执行的工作负载。您可以这样定义和运行它们:
var t = Task.Factory.StartNew(() => DoAction());
您不必关心使用的线程数,因为运行时环境会处理这个问题。因此,如果您有可能将工作负载分成更小的包,这些包可以并行执行,我将使用任务来完成这项工作。这种方法有其优点和缺点:
因此,我建议进行权衡:创建一个包含大约50个线程的线程池(使用
SetMaxThreads
方法)并对所有连接进行排队。这样,它的资源将比1000个线程少,并且处理连接的速度仍然相当快。这种方法有其优点和缺点:
因此,我建议进行权衡:创建一个包含大约50个线程的线程池(使用
SetMaxThreads
方法)并对所有连接进行排队。这样,它的资源将比1000个线程少,并且处理连接的速度仍然相当快。这两种方法都有创建过多线程的风险
线程的创建时间和内存消耗都很昂贵
看起来您的第二种方法,使用ThreadPool,应该会更好。由于超时时间较长(2秒),它仍将创建许多线程,但远远少于1000个
更好的方法(需要FX4)是使用Parallel.ForEach(…)
。但这也可能需要一些调整
一个真正好的解决方案是使用广播(UDP)协议来发现服务 这两种方法都有创建太多线程的风险 线程的创建时间和内存消耗都很昂贵 看起来您的第二种方法,使用ThreadPool,应该会更好。由于超时时间较长(2秒),它仍将创建许多线程,但远远少于1000个 更好的方法(需要FX4)是使用
Parallel.ForEach(…)
。但这也可能需要一些调整
一个真正好的解决方案是使用广播(UDP)协议来发现服务 现在我自己做了
..
..
var now = DateTime.Now;
foreach (var item in allIps)
{
new Thread(new ThreadStart(() =>
{
DoWork(item);
})).Start();
}
ThreadPool.QueueUserWorkItem(new WaitCallback(PrintTimeDifference), now);
..
..
var now = DateTime.Now;
foreach (var item in allIps)
{
var t = Task.Factory.StartNew(() =>
DoWork(item)
);
}
ThreadPool.QueueUserWorkItem(new WaitCallback(PrintTimeDifference), now);
}
static void PrintTimeDifference(object startTime)
{
Console.WriteLine("------------------Done!----------------------");
var s = (DateTime)startTime;
Console.WriteLine((DateTime.Now-s).Seconds);
}
var t = Task.Factory.StartNew(() => DoAction());
class Program {
private static long parallelIterations = 100;
private static long taskIterations = 100000000;
static void Main(string[] args) {
Console.WriteLine("Parallel Iterations: {0:n0}", parallelIterations);
Console.WriteLine("Task Iterations: {0:n0}", taskIterations);
Analyse("Simple Threads", ExecuteWorkWithSimpleThreads);
Analyse("ThreadPool Threads", ExecuteWorkWithThreadPoolThreads);
Analyse("Tasks", ExecuteWorkWithTasks);
Analyse("Parallel For", ExecuteWorkWithParallelFor);
Analyse("Async Delegates", ExecuteWorkWithAsyncDelegates);
}
private static void Analyse(string name, Action action) {
Stopwatch watch = new Stopwatch();
watch.Start();
action();
watch.Stop();
Console.WriteLine("{0}: {1} seconds", name.PadRight(20), watch.Elapsed.TotalSeconds);
}
private static void ExecuteWorkWithSimpleThreads() {
Thread[] threads = new Thread[parallelIterations];
for (long i = 0; i < parallelIterations; i++) {
threads[i] = new Thread(DoWork);
threads[i].Start();
}
for (long i = 0; i < parallelIterations; i++) {
threads[i].Join();
}
}
private static void ExecuteWorkWithThreadPoolThreads() {
object locker = new object();
EventWaitHandle waitHandle = new ManualResetEvent(false);
int finished = 0;
for (long i = 0; i < parallelIterations; i++) {
ThreadPool.QueueUserWorkItem((threadContext) => {
DoWork();
lock (locker) {
finished++;
if (finished == parallelIterations)
waitHandle.Set();
}
});
}
waitHandle.WaitOne();
}
private static void ExecuteWorkWithTasks() {
Task[] tasks = new Task[parallelIterations];
for (long i = 0; i < parallelIterations; i++) {
tasks[i] = Task.Factory.StartNew(DoWork);
}
Task.WaitAll(tasks);
}
private static void ExecuteWorkWithParallelFor() {
Parallel.For(0, parallelIterations, (n) => DoWork());
}
private static void ExecuteWorkWithAsyncDelegates() {
Action[] actions = new Action[parallelIterations];
IAsyncResult[] results = new IAsyncResult[parallelIterations];
for (long i = 0; i < parallelIterations; i++) {
actions[i] = DoWork;
results[i] = actions[i].BeginInvoke((result) => { }, null);
}
for (long i = 0; i < parallelIterations; i++) {
results[i].AsyncWaitHandle.WaitOne();
results[i].AsyncWaitHandle.Close();
}
}
private static void DoWork() {
//Thread.Sleep(TimeSpan.FromMilliseconds(taskDuration));
for (long i = 0; i < taskIterations; i++ ) { }
}
}