【问题标题】:Converting threaded to multi threaded code? ( task factory ?)将线程转换为多线程代码? (任务工厂?)
【发布时间】:2017-05-11 00:58:54
【问题描述】:

我有以下线程代码(我认为)表单,带有开始和取消按钮以及多行文本框,注释部分(//)来自工作单线程版本,下面我尝试改造多线程任务.factory 部件,但是它似乎可以很好地启动 powershell 命令(在任务管理器中显示),但程序无需等待每个“heavyOperation”的结果即可完成。

想法是同时启动所有四个HeavyOperation任务(ish)并等待每个返回结果并将结果附加到文本框

public partial class Form1 : Form
{
    Progress<string> progressReporter = new Progress<string>();
    CancellationTokenSource cancelSource;

    public Form1()
    {
        InitializeComponent();
        progressReporter.ProgressChanged += progressManager_ProgressChanged;
    }

    async private void btnStart_Click(object sender, EventArgs e)
    {
        btnStart.Enabled = false;
        btnCancel.Enabled = true;
        cancelSource = new CancellationTokenSource();
        //textBox1.Text = await Task.Run(() => PerfromTaskAction(cancelSource.Token));
        await Task.Run(() => PerfromTaskAction(cancelSource.Token));
        lblStatus.Text = "Completed.";           btnStart.Enabled = true;
        btnCancel.Enabled = false;
    }
    //private string PerfromTaskAction(CancellationToken ct)
    static void PerfromTaskAction(CancellationToken ct)
    {
        //StringBuilder sb = new StringBuilder();

        object[] arrObjects = new object[] { "SERVER1", "SERVER2", "SERVER3", "SERVER4" };

        foreach(object i in arrObjects)
        {
            //if (ct.IsCancellationRequested) break;
            //sb.Append(string.Format("{0}: {1}\r\n", HeavyOperation(i.ToString()),i));
            //((IProgress<string>)progressReporter).Report(string.Format("Now Checking: {0}...", i));
            Task.Factory.StartNew(() => HeavyOperation(i.ToString()));
        }
        //return sb.ToString();
    }
    void progressManager_ProgressChanged(object sender, string e)
    {          
        lblStatus.Invoke((Action)(() => lblStatus.Text = e));
    }
    //private string HeavyOperation(string i)
    public static void HeavyOperation(string i)
    {
        PowerShell ps = PowerShell.Create();
        ps.AddCommand("invoke-command");
        ps.AddParameter("computername", i);
        ps.AddParameter("scriptblock", ScriptBlock.Create("get-vmreplication | select State"));
        Collection<PSObject> result = ps.Invoke();
        //return result[0].Properties["State"].Value.ToString();
        Console.Write(result[0].Properties["State"].Value.ToString());
    }
    private void btnCancel_Click(object sender, EventArgs e)
    {
        cancelSource.Cancel();
    }

}

感谢收看

【问题讨论】:

标签: c# multithreading


【解决方案1】:

您还需要等待HeavyOperations 完成。

您可以为此目的使用Task.WhenAll。这是PerformTaskActionasync 版本,使用Task.WhenAll

我已经考虑了 Scott Chamberlain 的建议:

  1. 将不安全(在async-await 上下文中)Task.Factory.StartNew() 更改为Task.Run()
  2. 删除了PerformTaskAction()调用中不必要的await
  3. 通过外部Task.Run() 调用中缺少的CancellationToken

    静态异步任务 PerfromTaskAction(CancellationToken ct) { //StringBuilder sb = new StringBuilder();

         object[] arrObjects = new object[] { "SERVER1", "SERVER2", "SERVER3", "SERVER4" };
         IList<Task> tasks = new List<Task>(); // collect all tasks in single collection
         foreach( object i in arrObjects ) {
            //if (ct.IsCancellationRequested) break;
            //sb.Append(string.Format("{0}: {1}\r\n", HeavyOperation(i.ToString()),i));
            //((IProgress<string>)progressReporter).Report(string.Format("Now Checking: {0}...", i));
            tasks.Add(Task.Run(() => HeavyOperation(i.ToString())));
         }
    
         await Task.WhenAll(tasks).ConfigureAwait(false); // wait asynchronously for all tasks to complete
      }
    

既然 PerformTaskAction 是异步的,你还需要等待它。

最后你调用 PerformTaskAction,确保你也传递了 CancellationToken。

await Task.Run( ()=> PerformTaskAction(cancelSource.Token), cancelSource.Token);

【讨论】:

  • 没有必要在 Task.Run 中等待它有一个接受 Func&lt;Task&gt; 的重载,你也忘记将令牌传递给方法本身。 await Task.Run(() =&gt; PerfromTaskAction(cancelSource.Token), cancelSource.Token);
  • @ScottChamberlain,呆滞地指出。将修改我的答案以反映您的 cmets。意识到我在 async-await 周围仍然有一个不稳定的“心理模型”,这有点令人沮丧。在我看来,如果它是异步的,你等待......无论如何,感谢您的观察。
猜你喜欢
  • 1970-01-01
  • 2017-07-16
  • 1970-01-01
  • 2020-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-27
  • 1970-01-01
相关资源
最近更新 更多