我需要在Task(无限循环监控)中完成工作但是如何才能获得这项工作的结果?
我的逻辑是做错了吗?这是我认为的范围问题。
简化了一个例子: 变量是"第一个"我想"编辑"
namespace my{
public class Program{
public static void Main(string[] args){
Logic p = new Logic();
Task t = new Task(p.process);
t.Start();
Console.WriteLine(p.getVar());// result="first"
}
}
public class Logic{
public string test = "first";
public void process(){
while(true){
//If condition here
this.test = "edit";
}
}
public String getVar(){
return this.test;
}
}
}
答案 0 :(得分:0)
可以使用自定义event
完成。在你的情况下,它可能是这样的:
public event Action<string> OnValueChanged;
然后附上
p.OnValueChanged += (newValue) => Console.WriteLine(newValue);
别忘了解雇它
this.test = "edit";
OnValueChanged?.Invoke(this.test);
答案 1 :(得分:0)
任务不是线程,他们不需要.Start
来启动它们。所有示例和教程都显示了使用Task.Run
或Task.StartNew
的原因 - 任务是 promise ,函数将在未来的某个时刻执行并生成结果。它们将在任务计划程序决定应该从ThreadPool中提取的线程上运行。创建冷任务并致电.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.WhenAll
返回一个数组,其结果按创建任务的顺序排列。这允许检查索引以查找原始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:
ConcurrentQueue<string> _results=new ConcurrentQueue<string>();
public static (bool ok,string url) CheckThatService(string serviceUrl)
{
....
_results.Enqueue(someresult);
return (true,url);
}
如果我们想要定期报告进度,我们可以IProgress<T>
使用IProgress< T>
。
我们可以将所有监控代码放在一个单独的方法/类中,该方法/类接受带有进度对象的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,例如:
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;
Enabling Progress and Cancellation in Async APIs展示了如何使用CancellationTokenSource来实现监控类的另一个重要部分 - 取消它。监控方法可以定期检查取消令牌的状态,并在收集令牌时停止监控:
MyMonitor.Run()
在这种情况下,当引发CancellationToken时,循环将退出。通过不等待close(1); //closing stdout
newfd=dup(1); //newfd takes value of least available fd number
,我们可以继续处理主线程,直到发生信号监视应该停止的事件。
答案 2 :(得分:-1)
using (System.IO.StreamWriter file =
new System.IO.StreamWriter(@"jsonGonna.txt", true))
{
file.WriteLine(json);
}
方法在getVar
方法之前执行。
在调用process
方法之前,请确保等到任务完成。
getVar
如果您想了解有关Logic p = new Logic();
Task t = new Task(p.process);
t.Start();
t.Wait(); // Add this line!
Console.WriteLine(p.getVar());
方法的更多信息,请查看this link。