如何在任务中获得我的工作成果

时间:2018-05-28 08:07:32

标签: c# task

我需要在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;
        }
    }
}

3 个答案:

答案 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.RunTask.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