I am trying to calculate the average round-trip time for a collection of servers. In order to speed things up, I would like to perform the pings in parallel. I have written a function called AverageRoundtripTime()
and it seems to work, however, since I don't know very much about multi-threading, I am wondering if what I've done is okay. Please take a look at my code and let me know if it's okay or if there's a better way to achieve what I want:
public void Main()
{
// Collection of hosts.
List<String> hosts = new List<String>();
// 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<String> hosts)
{
// Collection of threads.
List<Thread> threads = new List<Thread>();
// Collection of ping replies.
List<PingReply> pingReplies = new List<PingReply>();
// 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);
}
Update:
Check out a related question that I asked:
The ping class has a method SendAsync
. This follows the Event-based Asynchronous Programming (EAP) pattern. Check out this article: http://msdn.microsoft.com/en-us/library/ee622454.aspx.
For a quick example here is a method I have that implements that article in a very basic fashion. You can basically call this as many times as you want and all the pings will be done asychronously.
class Program
{
public static string[] addresses = {"microsoft.com", "yahoo.com", "google.com"};
static void Main(string[] args)
{
List<Task<PingReply>> pingTasks = new List<Task<PingReply>>();
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<PingReply> PingAsync(string address)
{
var tcs = new TaskCompletionSource<PingReply>();
Ping ping = new Ping();
ping.PingCompleted += (obj, sender) =>
{
tcs.SetResult(sender.Reply);
};
ping.SendAsync(address, new object());
return tcs.Task;
}
}