如何使用C#并行执行多个“Ping”

我试图计算一组服务器的平均往返时间。 为了加快速度,我想并行执行ping操作。 我写了一个名为AverageRoundtripTime()的函数,但它似乎有用,因为我不太了解multithreading,我想知道我做的是否还可以。 请看看我的代码,让我知道它是否正常,或者是否有更好的方法来实现我想要的:

 public void Main() { // Collection of hosts. List hosts = new List(); // Add 100 hosts to the collection. for (Int32 i = 0; i < 100; ++i) hosts.Add("www.google.com"); // Display the average round-trip time for 100 hosts. Console.WriteLine(AverageRoundtripTime(hosts)); } public Double AverageRoundtripTime(IEnumerable hosts) { // Collection of threads. List threads = new List(); // Collection of ping replies. List pingReplies = new List(); // Loop through all host names. foreach (var host in hosts) { // Create a new thread. Thread thread = new Thread(() => { // Variable to hold the ping reply. PingReply reply = null; // Create a new Ping object and make sure that it's // disposed after we're finished with it. using (Ping ping = new Ping()) { reply = ping.Send(host); } // Get exclusive lock on the pingReplies collection. lock (pingReplies) { // Add the ping reply to the collection. pingReplies.Add(reply); } }); // Add the newly created thread to the theads collection. threads.Add(thread); // Start the thread. thread.Start(); } // Wait for all threads to complete foreach (Thread thread in threads) { thread.Join(); } // Calculate and return the average round-trip time. return pingReplies.Average(x => x.RoundtripTime); } 

更新:

查看我问过的相关问题:

Windows窗体应用程序中的任务并行库代码冻结 – 作为Windows控制台应用程序正常工作

ping类有一个SendAsync方法。 这遵循基于事件的异步编程(EAP)模式。 看看这篇文章: http : //msdn.microsoft.com/en-us/library/ee622454.aspx 。

这里有一个简单的例子,我有一个以非常基本的方式实现该文章的方法。 您基本上可以根据需要多次调用它,并且所有ping都将异步完成。

  class Program { public static string[] addresses = {"microsoft.com", "yahoo.com", "google.com"}; static void Main(string[] args) { List> pingTasks = new List>(); foreach (var address in addresses) { pingTasks.Add(PingAsync(address)); } //Wait for all the tasks to complete Task.WaitAll(pingTasks.ToArray()); //Now you can iterate over your list of pingTasks foreach (var pingTask in pingTasks) { //pingTask.Result is whatever type T was declared in PingAsync Console.WriteLine(pingTask.Result.RoundtripTime); } Console.ReadLine(); } static Task PingAsync(string address) { var tcs = new TaskCompletionSource(); Ping ping = new Ping(); ping.PingCompleted += (obj, sender) => { tcs.SetResult(sender.Reply); }; ping.SendAsync(address, new object()); return tcs.Task; } } 

使用Parallel.For和ConcurrentBag

  static void Main(string[] args) { Console.WriteLine(AverageRoundTripTime("www.google.com", 100)); Console.WriteLine(AverageRoundTripTime("www.stackoverflow.com", 100)); Console.ReadKey(); } static double AverageRoundTripTime(string host, int sampleSize) { ConcurrentBag values = new ConcurrentBag(); Parallel.For(1, sampleSize, (x, y) => values.Add(Ping(host))); return values.Sum(x => x) / sampleSize; } static double Ping(string host) { var reply = new Ping().Send(host); if (reply != null) return reply.RoundtripTime; throw new Exception("denied"); } 

//使用LINQ解决方案变得更简单了

 List hosts = new List(); for (Int32 i = 0; i < 100; ++i) hosts.Add("www.google.com"); var average = hosts.AsParallel().WithDegreeOfParallelism(64). Select(h => new Ping().Send(h).RoundtripTime).Average(); Console.WriteLine(average) 

也许像这样使用SendPingAsync :

 using (var ping = new Ping()) { var replies = await Task.WhenAll(hosts.Select(x => ping.SendPingAsync(x))) .ConfigureAwait(false); // false here ^ unless you want to schedule back to sync context ... process replies. } 

一个办法:

 internal class Utils { internal static PingReply Ping (IPAddress address, int timeout = 1000, int ttl = 64) { PingReply tpr = null; var p = new Ping (); try { tpr = p.Send (address, timeout, Encoding.ASCII.GetBytes ("oooooooooooooooooooooooooooooooo"), new PingOptions (ttl, true)); } catch (Exception ex) { tpr = null; } finally { if (p != null) p.Dispose (); p = null; } return tpr; } internal static List PingAddresses (List addresses, int timeout = 1000, int ttl = 64) { var ret = addresses .Select (p => Ping (p, timeout, ttl)) .Where (p => p != null) .Where (p => p.Status == IPStatus.Success) .Select (p => p).ToList (); return ret; } internal static Task PingAddressesAsync (List addresses, Action>> endOfPing, int timeout = 1000, int ttl = 64) { return Task.Factory.StartNew> (() => Utils.PingAddresses ( addresses, timeout, ttl)).ContinueWith (t => endOfPing (t)); } } 

并使用:

 Console.WriteLine ("start"); Utils.PingAddressesAsync (new List () { IPAddress.Parse ("192.168.1.1"), IPAddress.Parse ("192.168.1.13"), IPAddress.Parse ("192.168.1.49"), IPAddress.Parse ("192.168.1.200") }, delegate(Task> tpr) { var lr = tpr.Result; Console.WriteLine ("finish with " + lr.Count.ToString () + " machine found"); foreach (var pr in lr) { Console.WriteLine (pr.Address.ToString ()); } }); Console.WriteLine ("execute"); Console.ReadLine ();