12

サーバーのコレクションの平均往復時間を計算しようとしています。スピードアップするために、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);

}

アップデート:

私が尋ねた関連する質問をチェックしてください:

タスク並列ライブラリ コードが Windows フォーム アプリケーションでフリーズする - Windows コンソール アプリケーションとして正常に動作する

4

6 に答える 6

14

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<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;
    }
}
于 2012-11-15T20:49:34.197 に答える
5

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");
    }
于 2012-11-15T20:55:32.927 に答える
4

// 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)
于 2014-06-26T11:33:25.560 に答える
1

たぶん、次のように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.
}
于 2015-04-15T18:10:15.490 に答える