“如何执行多个”;Pings";并行使用C#

“如何执行多个”;Pings";并行使用C#,c#,multithreading,ping,C#,Multithreading,Ping,我试图计算一组服务器的平均往返时间。为了加快速度,我想并行执行ping。我编写了一个名为AverageRoundtripTime()的函数,它似乎可以工作,但是,由于我对多线程知之甚少,我想知道我所做的是否可以。请查看我的代码,并告诉我是否可以,或者是否有更好的方法来实现我的目标: public void Main() { // Collection of hosts. List<String> hosts = new List<String>();

我试图计算一组服务器的平均往返时间。为了加快速度,我想并行执行ping。我编写了一个名为
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");
    }
}