“如何执行多个”;Pings";并行使用C#
我试图计算一组服务器的平均往返时间。为了加快速度,我想并行执行ping。我编写了一个名为“如何执行多个”;Pings";并行使用C#,c#,multithreading,ping,C#,Multithreading,Ping,我试图计算一组服务器的平均往返时间。为了加快速度,我想并行执行ping。我编写了一个名为AverageRoundtripTime()的函数,它似乎可以工作,但是,由于我对多线程知之甚少,我想知道我所做的是否可以。请查看我的代码,并告诉我是否可以,或者是否有更好的方法来实现我的目标: public void Main() { // Collection of hosts. List<String> hosts = new List<String>();
AverageRoundtripTime()
的函数,它似乎可以工作,但是,由于我对多线程知之甚少,我想知道我所做的是否可以。请查看我的代码,并告诉我是否可以,或者是否有更好的方法来实现我的目标:
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);
}
public void Main()
{
//主机集合。
列表主机=新列表();
//将100台主机添加到集合中。
对于(int32i=0;i<100;++i)主机。添加(“www.google.com”);
//显示100台主机的平均往返时间。
Console.WriteLine(AverageRoundtripTime(主机));
}
public Double AverageRoundtripTime(IEnumerable hosts)
{
//线程的集合。
列表线程=新列表();
//收集ping回复。
List pingReplies=新列表();
//遍历所有主机名。
foreach(主机中的var主机)
{
//创建一个新线程。
线程线程=新线程(()=>
{
//变量来保存ping回复。
PingReply=null;
//创建一个新的Ping对象并确保
//在我们完成后处理。
使用(Ping=new Ping())
{
回复=ping.Send(主机);
}
//获取pingReplies集合的独占锁。
锁(ping回复)
{
//将ping回复添加到集合中。
添加(回复);
}
});
//将新创建的线程添加到theads集合。
线程。添加(线程);
//启动线程。
thread.Start();
}
//等待所有线程完成
foreach(线程中的线程)
{
thread.Join();
}
//计算并返回平均往返时间。
返回pingrepries.Average(x=>x.RoundtripTime);
}
更新:
看看我问的一个相关问题:
ping类有一个方法
SendAsync
。这遵循基于事件的异步编程(EAP)模式。请查看本文:
举个简单的例子,我有一个方法,它以一种非常基本的方式实现了这篇文章。基本上,您可以根据需要多次调用它,所有ping都将异步完成
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;
}
}
类程序
{
公共静态字符串[]地址={“microsoft.com”、“yahoo.com”、“google.com”};
静态void Main(字符串[]参数)
{
List pingTasks=新列表();
foreach(地址中的变量地址)
{
添加(PingAsync(地址));
}
//等待所有任务完成
Task.WaitAll(pingTasks.ToArray());
//现在,您可以遍历任务列表
foreach(pingTasks中的var pingTask)
{
//结果是PingAsync中声明的任何类型T
Console.WriteLine(pingTask.Result.RoundtripTime);
}
Console.ReadLine();
}
静态任务PingAsync(字符串地址)
{
var tcs=new TaskCompletionSource();
Ping Ping=新Ping();
ping.PingCompleted+=(对象、发送方)=>
{
tcs.SetResult(sender.Reply);
};
ping.sendaync(地址,新对象());
返回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<double> values = new ConcurrentBag<double>();
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");
}
static void Main(字符串[]args)
{
WriteLine(AverageRoundTripTime(“www.google.com”,100));
WriteLine(AverageRoundTripTime(“www.stackoverflow.com”,100));
Console.ReadKey();
}
静态double AverageRoundTripTime(字符串主机,int-sampleSize)
{
ConcurrentBag值=新ConcurrentBag();
Parallel.For(1,sampleSize,(x,y)=>values.Add(Ping(主机));
返回值.Sum(x=>x)/sampleSize;
}
静态双Ping(字符串主机)
{
var reply=new Ping().Send(主机);
如果(回复!=null)
返回reply.RoundtripTime;
抛出新异常(“拒绝”);
}
//使用LINQ解决方案变得更简单
List<String> hosts = new List<String>();
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)
List hosts=new List();
对于(int32i=0;i<100;++i)主机。添加(“www.google.com”);
var average=hosts.AsParallel(),带有degreeofparallelism(64)。
选择(h=>newping().Send(h).RoundtripTime.Average();
控制台写入线(平均值)
可以这样使用:
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<PingReply> PingAddresses (List<IPAddress> 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<IPAddress> addresses, Action<Task<List<PingReply>>> endOfPing, int timeout = 1000, int ttl = 64)
{
return Task.Factory.StartNew<List<PingReply>> (() => Utils.PingAddresses (
addresses, timeout, ttl)).ContinueWith (t => endOfPing (t));
}
}
内部类Utils
{
内部静态Ping应答Ping(IPAddress地址,int timeout=1000,int ttl=64)
{
PingReply tpr=null;
var p=新Ping();
试一试{
tpr=p.发送(地址,
超时,
Encoding.ASCII.GetBytes(“oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo”),
新的PingOptions(ttl,true));
}捕获(例外情况除外){
tpr=null;
}最后{
如果(p!=null)
p、 处置();
p=零;
}
返回tpr;
}
内部静态列表地址(列表地址,int timeout=1000,int ttl=64)
{
var ret=地址
.选择(p=>Ping(p,timeout,ttl))
.其中(p=>p!=null)
.Where(p=>p.Status==IPStatus.Success)
.Select(p=>p.ToList();
返回ret;
}
内部静态任务PingAddressesAsync(列表地址、操作结束、int超时=1000、int ttl=64)
{
返回Task.Factory.StartNew(()=>Utils.PingAddresses(
地址,超时,ttl))。继续使用(t=>endOfPing(t));
}
}
并使用:<
Console.WriteLine ("start");
Utils.PingAddressesAsync (new List<IPAddress> () {
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<List<PingReply>> 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 ();
public class NetworkHeartbeat
{
private static object lockObj = new object();
public bool Running { get; private set; }
public int PingTimeout { get; private set; }
public int HeartbeatDelay { get; private set; }
public IPAddress[] EndPoints { get; private set; }
public int Count => EndPoints.Length;
public PingReply[] PingResults { get; private set; }
private Ping[] Pings { get; set; }
public NetworkHeartbeat(IEnumerable<IPAddress> hosts, int pingTimeout, int heartbeatDelay)
{
PingTimeout = pingTimeout;
HeartbeatDelay = heartbeatDelay;
EndPoints = hosts.ToArray();
PingResults = new PingReply[EndPoints.Length];
Pings = EndPoints.Select(h => new Ping()).ToArray();
}
public async void Start()
{
if (!Running)
{
try
{
Debug.WriteLine("Heartbeat : starting ...");
// set up the tasks
var chrono = new Stopwatch();
var tasks = new Task<PingReply>[Count];
Running = true;
while (Running)
{
// set up and run async ping tasks
OnPulseStarted(DateTime.Now, chrono.Elapsed);
chrono.Restart();
for (int i = 0; i < Count; i++)
{
tasks[i] = PingAndUpdateAsync(Pings[i], EndPoints[i], i);
}
await Task.WhenAll(tasks);
for (int i = 0; i < tasks.Length; i++)
{
var pingResult = tasks[i].Result;
if (pingResult != null)
{
if (PingResults[i] == null)
{
if (pingResult.Status == IPStatus.Success)
OnPingUp(i);
}
else if (pingResult.Status != PingResults[i].Status)
{
if (pingResult.Status == IPStatus.Success)
OnPingUp(i);
else if (PingResults[i].Status == IPStatus.Success)
OnPingDown(i);
}
}
else
{
if (PingResults[i] != null && PingResults[i].Status == IPStatus.Success)
OnPingUp(i);
}
PingResults[i] = tasks[i].Result;
Debug.WriteLine("> Ping [" + PingResults[i].Status.ToString().ToUpper() + "] at " + EndPoints[i] + " in " + PingResults[i].RoundtripTime + " ms");
}
OnPulseEnded(DateTime.Now, chrono.Elapsed);
// heartbeat delay
var delay = Math.Max(0, HeartbeatDelay - (int)chrono.ElapsedMilliseconds);
await Task.Delay(delay);
}
Debug.Write("Heartbeat : stopped");
}
catch (Exception)
{
Debug.Write("Heartbeat : stopped after error");
Running = false;
throw;
}
}
else
{
Debug.WriteLine("Heartbeat : already started ...");
}
}
public void Stop()
{
Debug.WriteLine("Heartbeat : stopping ...");
Running = false;
}
private async Task<PingReply> PingAndUpdateAsync(Ping ping, IPAddress epIP, int epIndex)
{
try
{
return await ping.SendPingAsync(epIP, PingTimeout);
}
catch (Exception ex)
{
Debug.Write("-[" + epIP + "] : error in SendPing()");
OnPingError(epIndex, ex);
return null;
}
}
// Event on ping errors
public event EventHandler<PingErrorEventArgs> PingError;
public class PingErrorEventArgs : EventArgs
{
public int EndPointIndex { get; private set; }
public Exception InnerException { get; private set; }
public PingErrorEventArgs(int epIndex, Exception ex)
{
EndPointIndex = epIndex;
InnerException = ex;
}
}
private void OnPingError(int epIndex, Exception ex) => PingError?.Invoke(this, new PingErrorEventArgs(epIndex, ex));
// Event on ping Down
public event EventHandler<int> PingDown;
private void OnPingDown(int epIndex)
{
Debug.WriteLine("# Ping [DOWN] at " + EndPoints[epIndex]);
PingDown?.Invoke(this, epIndex);
}
// Event on ping Up
public event EventHandler<int> PingUp;
private void OnPingUp(int epIndex)
{
Debug.WriteLine("# Ping [UP] at " + EndPoints[epIndex] );
PingUp?.Invoke(this, epIndex);
}
// Event on pulse started
public event EventHandler<PulseEventArgs> PulseStarted;
public class PulseEventArgs : EventArgs
{
public DateTime TimeStamp { get; private set; }
public TimeSpan Delay { get; private set; }
public PulseEventArgs(DateTime date, TimeSpan delay)
{
TimeStamp = date;
Delay = delay;
}
}
private void OnPulseStarted(DateTime date, TimeSpan delay)
{
Debug.WriteLine("# Heartbeat [PULSE START] after " + (int)delay.TotalMilliseconds + " ms");
PulseStarted?.Invoke(this, new PulseEventArgs(date, delay));
}
// Event on pulse ended
public event EventHandler<PulseEventArgs> PulseEnded;
private void OnPulseEnded(DateTime date, TimeSpan delay)
{
PulseEnded?.Invoke(this, new PulseEventArgs(date, delay));
Debug.WriteLine("# Heartbeat [PULSE END] after " + (int)delay.TotalMilliseconds + " ms");
}
}