C# 我怎样才能在一项任务中得到工作的结果
我需要在一个任务中做一项工作(无限循环用于监控),但我如何才能得到这项工作的结果 我做这件事的逻辑我做错了?我认为这是一个范围问题 有一个简化的例子: 变量是“first”,我想要“edit”C# 我怎样才能在一项任务中得到工作的结果,c#,task,C#,Task,我需要在一个任务中做一项工作(无限循环用于监控),但我如何才能得到这项工作的结果 我做这件事的逻辑我做错了?我认为这是一个范围问题 有一个简化的例子: 变量是“first”,我想要“edit” getVar方法在过程方法之前执行。 确保在调用getVar方法之前等待任务完成 Logic p = new Logic(); Task t = new Task(p.process); t.Start(); t.Wait(); // Add this line! Console.WriteLine(p.
getVar
方法在过程
方法之前执行。
确保在调用getVar
方法之前等待任务完成
Logic p = new Logic();
Task t = new Task(p.process);
t.Start();
t.Wait(); // Add this line!
Console.WriteLine(p.getVar());
如果您想了解有关
等待
方法的更多信息,请检查。可以使用自定义事件来完成。在您的情况下,它可能类似于:
public event Action<string> OnValueChanged;
别忘了开枪
this.test = "edit";
OnValueChanged?.Invoke(this.test);
任务不是线程,它们不需要调用.Start
来启动它们。所有示例和教程都说明了Task.Run
或Task.StartNew
的用法,原因是任务承诺函数将在将来某个时间执行并产生结果。当任务调度器决定它们应该运行时,它们将在从线程池中提取的线程上运行。创建冷任务并调用.Start
并不能保证它们会启动,这只会使代码更难阅读
在最简单的情况下,轮询远程HTTP端点可以简单到:
public static async Task Main()
{
var client=new HttpClient(serverUrl);
while(true)
{
var response=await client.GetAsync(relativeServiceUrl);
if(!response.IsSuccessStatusCode)
{
//That was an error, do something with it
}
await Task.Delay(1000);
}
}
无需启动新任务,因为GetAsync
是异步的。WCF和ADO.NET还提供异步执行方法
如果没有要调用的异步方法,或者如果我们需要在异步调用之前执行一些繁重的工作,我们可以使用Task.Run并行启动一个方法并等待它完成:
public bool CheckThatService(string serviceUrl)
{
....
}
public static async Task Main()
{
var url="...";
//...
while(true)
{
var ok=Task.Run(()=>CheckThatService(url));
if(!ok)
{
//That was an error, do something with it
}
await Task.Delay(1000);
}
}
如果我们想并行测试多个系统呢?我们可以并行启动多个任务,等待所有任务完成并检查其结果:
public static async Task Main()
{
var urls=new[]{"...","..."};
//...
while(true)
{
var tasks=urls.Select(url=>Task.Run(()=>CheckThatService(url));
var responses=await Task.WhenAll(tasks);
foreach(var response in responses)
{
///Check the value, due something
}
await Task.Delay(1000);
}
}
Task.whalll
按创建任务的顺序返回结果数组。这允许检查索引以查找原始URL。更好的方法是同时返回结果和url,例如使用元组:
public static (bool ok,string url) CheckThatService(string serviceUrl)
{
....
return (true,url);
}
代码不会有太大变化:
var tasks=urls.Select(url=>Task.Run(()=>CheckThatService(url));
var responses=await Task.WhenAll(tasks);
foreach(var response in responses.Where(resp=>!resp.ok))
{
///Check the value, due something
}
如果我们想存储所有调用的结果呢?无法使用列表或队列,因为它们不是线程安全的。我们可以使用以下方法:
ConcurrentQueue<string> _results=new ConcurrentQueue<string>();
public static (bool ok,string url) CheckThatService(string serviceUrl)
{
....
_results.Enqueue(someresult);
return (true,url);
}
ConcurrentQueue_results=new ConcurrentQueue();
公共静态(bool ok,字符串url)检查服务(字符串服务url)
{
....
_结果:排队(someresult);
返回(true,url);
}
如果我们想定期报告进度,我们可以使用IProgress
,如中所示
我们可以将所有监控代码放在一个单独的方法/类中,该方法/类接受带有进度对象的IProgress
参数,该进度对象可以报告成功、错误消息以及导致它们的URL,例如:
class MonitorDTO
{
public string Url{get;set;}
public bool Success{get;set;}
public string Message{get;set;}
public MonitorDTO(string ulr,bool success,string msg)
{
//...
}
}
class MyMonitor
{
string[] _urls=url;
public MyMonitor(string[] urls)
{
_urls=url;
}
public Task Run(IProgress<MonitorDTO> progress)
{
while(true)
{
var ok=Task.Run(()=>CheckThatService(url));
if(!ok)
{
_progress.Report(new MonitorDTO(ok,url,"some message");
}
await Task.Delay(1000);
}
}
}
类监视器
{
公共字符串Url{get;set;}
公共bool成功{get;set;}
公共字符串消息{get;set;}
公共监视器DTO(字符串ulr、bool success、字符串msg)
{
//...
}
}
类MyMonitor
{
字符串[]url=url;
公共MyMonitor(字符串[]URL)
{
_url=url;
}
公共任务运行(IProgress进程)
{
while(true)
{
var ok=Task.Run(()=>CheckThatService(url));
如果(!ok)
{
_progress.Report(新的MonitorDTO(ok,url,“一些消息”);
}
等待任务。延迟(1000);
}
}
}
此类可按以下方式使用:
public static async Task Maim()
{
var ulrs=new[]{....};
var monitor=new MyMonitor(urls);
var progress=new Progress<MonitorDTO>(pg=>{
Console.WriteLine($"{pg.Success} for {pg.Url}: {pg.Message}");
});
await monitor.Run(progress);
}
公共静态异步任务Maim()
{
var ulrs=新[]{….};
var monitor=新的MyMonitor(URL);
变量进度=新进度(pg=>{
WriteLine($“{pg.Url}:{pg.Message}的{pg.Success}”);
});
等待监视器。运行(进度);
}
演示如何使用CancellationTokenSource实现监视类的另一个重要部分-取消它。监视方法可以定期检查取消令牌的状态,并在引发时停止监视:
public Task Run(IProgress<MonitorDTO> progress,CancellationToken ct)
{
while(!ct.IsCancellationRequested)
{
//...
}
}
public static async Task Maim()
{
var ulrs=new[]{....};
var monitor=new MyMonitor(urls);
var progress=new Progress<MonitorDTO>(pg=>{
Console.WriteLine($"{pg.Success} for {pg.Url}: {pg.Message}");
});
var cts = new CancellationTokenSource();
//Not awaiting yet!
var monitorTask=monitor.Run(progress,cts.Token);
//Keep running until the first keypress
Console.ReadKey();
//Cancel and wait for the monitoring class to gracefully stop
cts.Cancel();
await monitorTask;
公共任务运行(IProgress progress,CancellationToken ct)
{
而(!ct.iscancellationrequest)
{
//...
}
}
公共静态异步任务Maim()
{
var ulrs=新[]{….};
var monitor=新的MyMonitor(URL);
变量进度=新进度(pg=>{
WriteLine($“{pg.Url}:{pg.Message}的{pg.Success}”);
});
var cts=新的CancellationTokenSource();
//还没等呢!
var monitorTask=monitor.Run(进度,cts.Token);
//继续运行,直到第一次按键
Console.ReadKey();
//取消并等待监视类正常停止
cts.Cancel();
等待监控任务;
在这种情况下,当发出CancellationToken时,循环将退出
我们可以继续在主线程上工作,直到发生信号监视应该停止的事件为止。您正在启动任务,但不是等待它完成。不过,您的描述与代码不匹配-在这种情况下,等待任务完成是有意义的,但在您描述无限长l的情况下则没有意义oop。无限循环在什么时候会提供结果?首先,你没有真正解释你想要什么。你希望无限循环产生什么样的结果?可能是通知?第一个成功的结果?第二,任务不是线程。你不需要.Start
来启动它们。只需使用Task.Run(somethod)
。您可以等待它完成等待任务。运行(…)
并使用var result=await Task.Run(…)分配任何结果
@Steve你想做什么?轮询服务并记录每个结果?或轮询服务并记录第一次故障?你想在第一次故障后继续循环吗?这是用于网络监控的,因此可以在循环中以不规则的间隔获取帧。这些帧存储在列表中,与我的字符串var相同在我的例子中。这就是为什么我不能等待任务的结束。事实上,我希望
public static async Task Maim()
{
var ulrs=new[]{....};
var monitor=new MyMonitor(urls);
var progress=new Progress<MonitorDTO>(pg=>{
Console.WriteLine($"{pg.Success} for {pg.Url}: {pg.Message}");
});
await monitor.Run(progress);
}
public Task Run(IProgress<MonitorDTO> progress,CancellationToken ct)
{
while(!ct.IsCancellationRequested)
{
//...
}
}
public static async Task Maim()
{
var ulrs=new[]{....};
var monitor=new MyMonitor(urls);
var progress=new Progress<MonitorDTO>(pg=>{
Console.WriteLine($"{pg.Success} for {pg.Url}: {pg.Message}");
});
var cts = new CancellationTokenSource();
//Not awaiting yet!
var monitorTask=monitor.Run(progress,cts.Token);
//Keep running until the first keypress
Console.ReadKey();
//Cancel and wait for the monitoring class to gracefully stop
cts.Cancel();
await monitorTask;