Ada*_*zek 4 .net c# multithreading ping async-await
我需要创建应用程序,它将在循环中ping多个地址.我在stackoverflow上阅读了很多例子,最后得到了工作代码:
public void Check(List<string> addresses)
{
List<Task<PingReply>> pingTasks = new List<Task<PingReply>>();
foreach (string address in addresses)
{
pingTasks.Add(PingAsync(address));
}
Task.Factory.ContinueWhenAll(pingTasks.ToArray(), _ => { }).ContinueWith(t =>
{
StringBuilder pingResult = new StringBuilder();
foreach (var pingTask in pingTasks)
{
pingResult.Append(pingTask.Result.Address);
pingResult.Append(" ");
pingResult.Append(pingTask.Result.Status);
pingResult.Append(" ");
pingResult.Append(pingTask.Result.RoundtripTime.ToString());
pingResult.Append(" \n");
}
Console.WriteLine(pingResult.ToString());
},
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());
}
public static Task<PingReply> PingAsync(string address)
{
var tcs = new TaskCompletionSource<PingReply>();
using (Ping ping = new Ping())
{
ping.PingCompleted += (obj, sender) =>
{
tcs.SetResult(sender.Reply);
};
ping.SendAsync(address, new object());
}
return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)
现在我需要更改此代码以使用await和async,然后在循环中使用interval执行此操作.在这里我的问题开始了.我不知道如何在这种情况下使用异步,我读了很多文章,现在我很困惑,因为我的代码仍然不起作用.你能一步一步地向我解释如何改变我的代码以便等待吗?你能解释一下我怎么能在执行间隔的循环中把它放进去?我试图把整个'Check'函数放到循环中并在最后添加Thread.Sleep(interval),但我有这种奇怪的感觉,我做错了什么/不高效.我需要在1秒内ping 400台服务器.它甚至可能吗?问候
更新1: 到目前为止我有代码:
using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net.NetworkInformation;
using System.Linq;
namespace Pinging
{
class CheckPing
{
public async Task LoopAndCheckPingAsync(List<string> addresses)
{
while (true)
{
var ping = new Ping();
var pingTasks = addresses.Select(address => ping.SendPingAsync(address));
await Task.WhenAll(pingTasks);
StringBuilder pingResultBuilder = new StringBuilder();
foreach (var pingReply in pingTasks)
{
pingResultBuilder.Append(pingReply.Result.Address);
pingResultBuilder.Append(" ");
pingResultBuilder.Append(pingReply.Result.Status);
pingResultBuilder.Append(" ");
pingResultBuilder.Append(pingReply.Result.RoundtripTime.ToString());
pingResultBuilder.AppendLine();
}
Console.WriteLine(pingResultBuilder.ToString());
await Task.Delay(TimeSpan.FromMinutes(5));
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
并致电:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Pinging
{
public class Class1
{
static void Main()
{
List<string> addresses = new List<string>() { "www.google.pl", "212.77.100.101" };
CheckPing c = new CheckPing();
Task.Factory.StartNew(() => c.LoopAndCheckPingAsync(addresses));
Console.Read();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我尝试用不同的方式从Main调用LoopAndCheckPingAsync,但仍然冻结.这是我的最后一次尝试.
编辑2: 我做了一些更改以查看应用程序性能,现在我的代码如下所示:
using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net.NetworkInformation;
using System.Linq;
namespace Pinging
{
class CheckPing
{
public async Task LoopAndCheckPingAsync(List<string> addresses)
{
while (true)
{
var pingTasks = addresses.Select(address =>
{
return new Ping().SendPingAsync(address);
});
await Task.WhenAll(pingTasks);
StringBuilder pingResultBuilder = new StringBuilder();
foreach (var pingReply in pingTasks)
{
pingResultBuilder.Append(pingReply.Result.Address);
pingResultBuilder.Append(" ");
pingResultBuilder.Append(pingReply.Result.Status);
pingResultBuilder.Append(" ");
pingResultBuilder.Append(pingReply.Result.RoundtripTime.ToString());
pingResultBuilder.AppendLine();
}
Console.WriteLine(pingResultBuilder.ToString());
Functions.counter++;
if (Functions.counter >= 100) break;
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Pinging
{
public class Class1
{
static void Main()
{
List<string> addresses = Functions.Read(@"C:\Users\Adam\Desktop\addresses.csv");
Functions.start = DateTime.Now;
CheckPing c = new CheckPing();
c.LoopAndCheckPingAsync(addresses).Wait();
Console.WriteLine(Functions.counter);
Console.Read();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我正在使用从文件中获取的标准站点地址:
www.google.com
www.yahoo.com
www.live.com
www.msn.com
www.facebook.com
www.youtube.com
www.microsoft.com
www.wikipedia.org
www.myspace.com
www.ebay.com
www.aol.com
www.ask.com
www.craigslist.org
www.blogspot.com
www.answers.com
www.about.com
www.amazon.com
www.mapquest.com
www.windows.com
www.adobe.com
www.photobucket.com
www.wordpress.com
www.go.com
www.paypal.com
www.walmart.com
www.reference.com
www.cnn.com
www.twitter.com
www.imdb.com
www.flickr.com
www.att.com
www.cnet.com
www.irs.gov
www.whitepages.com
www.yellowpages.com
www.comcast.net
www.target.com
www.simplyhired.com
www.webmd.com
www.weather.com
www.blogger.com
www.bankofamerica.com
www.apple.com
www.chase.com
www.bizrate.com
www.hulu.com
www.merriam-webster.com
www.geocities.com
www.ehow.com
www.ezinearticles.com
Run Code Online (Sandbox Code Playgroud)
编辑3: 现在一切都很完美,但这是我需要处理的另一个问题.当我在5分钟后测试100000次ping时,我的内存异常.有办法以某种方式处理这个?也许划分为街区并摧毁旧班级?
编辑4: 错误内容:
System.OutOfMemoryException未处理HResult = -2147024882 Message =抛出了类型'System.OutOfMemoryException'的异常.Source = mscorlib StackTrace:System.Net上的System.InvalidOperationException..ctor(String message,Exception innerException)中的System.Exception.Init()处于System.Net的System.Net.NetworkInformation.PingException..ctor(String message,Exception innerException). NetworkInformation.Ping.ContinueAsyncSend(对象状态)在System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(对象状态)在System.Threading.ExecutionContext.RunInternal(的ExecutionContext的ExecutionContext,ContextCallback回调,对象的状态,布尔preserveSyncCtx)在System.Threading.ExecutionContext.Run (ExecutionContext executionContext,ContextCallback回调,Object状态,Boolean preserveSyncCtx)System.Threading.Qhreading.ThreadPoolWorkIue上的System.Threading.QuereadingUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
InnerException :
编辑5添加使用语句后,我得到"没有足够的存储空间来处理此命令"错误:
System.AggregateException未处理HResult = -2146233088
消息=发生一个或多个错误.Source = mscorlib StackTrace:位于System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout,CancellationToken cancellationToken)的System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions),位于Pinging的System.Threading.Tasks.Task.Wait()处.Class1.Main()在System.AppDomain._nExecuteAssembly(RuntimeAssembly组件,字串[] args)在System.AppDomain.ExecuteAssembly(字符串assemblyFile,证据assemblySecurity,字串[] args)在Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly( )在System.Threading.ThreadHelper.ThreadStart_Context(对象状态)在System.Threading.ExecutionContext.RunInternal(的ExecutionContext的ExecutionContext,ContextCallback回调,对象的状态,布尔preserveSyncCtx)在System.Threading.ExecutionContext.Run(的ExecutionContext的ExecutionContext,ContextCallback回调,对象System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback回调,对象状态)中的state,Boolean preserveSyncCtx)at System.Threading.ThreadHelper.ThreadStart()InnerException:System.Net.NetworkInformation.PingException HResult = -2146233079 Message = Ping请求期间发生异常.来源= mscorlib程序堆栈跟踪:在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(工作任务)在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(工作任务)在System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()在ping命令. CheckPing.d__2.MoveNext()的InnerException:System.ApplicationException的HResult = -2147024888消息=没有足够的存储可用来处理该命令(从HRESULT异常:0x80070008)源= mscorlib程序堆栈跟踪:在System.Threading.ThreadPool.RegisterWaitForSingleObjectNative(WaitHandle的WaitHandle的,对象的状态,UInt32的timeOutInterval,布尔executeOnlyOnce,registeredWaitHandle registeredWaitHandle,在System.Threading.ThreadPool.RegisterWaitForSingleObject(WaitHandle的waitObject,WaitOrTimerCallback回调,对象的状态,UInt32的millisecondsTimeOutInterval,布尔executeOnlyOnce,StackCrawlMark&stackMark,布尔compressStack StackCrawlMark&stackMark,布尔compressStack))在System.Threading.Threa dPool.RegisterWaitForSingleObject(WaitHandle的waitObject,WaitOrTimerCallback回调,对象的状态,的Int32 millisecondsTimeOutInterval,布尔executeOnlyOnce)在System.Net.NetworkInformation.Ping.InternalSend(ip地址地址,字节[]缓冲液,的Int32超时,PingOptions选项,布尔异步)在系统. Net.NetworkInformation.Ping.ContinueAsyncSend(Object state)InnerException:
让我们来看看我们想做的事情:
我们想在第一次执行方法时开始while循环
我们想要生成一堆将用于发送ping请求的任务.为此,我们可以使用Ping.SendPingAsync.我们将使用地址列表来投影每个元素Enumerable.Select
我们将等待,直到所有任务完成执行.为此,我们将await继续Task.WhenAll.
当所有任务完成执行ping请求后,我们将使用foreach循环迭代它们.
我们将等待通话之间的间隔时间.我们不会使用Thread.Sleep,因为这是一个阻止电话.我们将使用Task.Delaywill internaly使用a Timer.当我们等待它时,控制将回到调用我们的方法.
这是它的出现方式:
private static async Task LoopAndCheckPingAsync(List<string> addresses)
{
StringBuilder pingResultBuilder = new StringBuilder();
while (true)
{
var pingTasks = addresses.Select(address =>
{
using (var ping = new Ping())
{
return ping.SendPingAsync(address);
}
}).ToList();
await Task.WhenAll(pingTasks);
foreach (var pingReply in pingTasks)
{ pingResultBuilder.Append(pingReply.Result.Address);
pingResultBuilder.Append(" ");
pingResultBuilder.Append(pingReply.Result.Status);
pingResultBuilder.Append(" ");
pingResultBuilder.Append(pingReply.Result.RoundtripTime.ToString());
pingResultBuilder.AppendLine();
}
Console.WriteLine(pingResultBuilder.ToString());
pingResultBuilder.Clear();
await Task.Delay(TimeSpan.FromMinutes(5));
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,该方法现在返回a Task而不是void,因为我们需要await在我们的方法上(注意async一旦开始使用它,就会在代码库中传播).
编辑
在深入了解Ping该类之后,显然我们无法在同一个Ping实例上执行多个ping请求(查看Ping.CheckStart哪些检查是否有正在进行的请求,以及是否有抛出InvalidOperationException),这正是我们在Select方法中所做的.要解决该问题,我们可以Ping为每个请求创建一个类的实例.请注意,这会给您的应用程序增加一些内存压力.如果同时发出1000个请求,则意味着Ping在发出这些请求时,内存中将有1000个类实例.
另外需要注意的是,您正在内部使用ThreadPoolSynchronizationContext的控制台应用程序中运行.无需调用Task.Run执行我们的方法,您可以用来Task.Wait在发出请求时保持控制台应用程序处于活动状态.最好使用Wait,因此我们可以看到是否有任何异常从我们的方法传播.
static void Main()
{
List<string> addresses = new List<string>() { "www.google.pl", "212.77.100.101" };
CheckPing c = new CheckPing();
c.LoopAndCheckPingAsync(addresses).Wait();
}
Run Code Online (Sandbox Code Playgroud)