将线程转换为多线程代码? (任务工厂?)

时间:2017-05-09 08:29:02

标签: c# multithreading

我有以下线程代码(我认为)表单,带有一个启动和取消按钮以及一个多行文本框,注释部分(//)来自工作单线程版本,下面我试图改进多线程任务.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();
    }

}

感谢您寻找

1 个答案:

答案 0 :(得分:2)

您还需要等待HeavyOperation完成。

您可以将Task.WhenAll用于此目的。以下是async的{​​{1}}版本,使用PerformTaskAction

我考虑过 Scott Chamberlain 的建议:

  1. 将不安全(在Task.WhenAll上下文中)async-await更改为Task.Factory.StartNew()
  2. 在调用Task.Run()
  3. 时删除了不必要的await
  4. 在外部PerformTaskAction()电话

    中传递了丢失的CancellationToken

    static async Task PerfromTaskAction(CancellationToken ct){          // StringBuilder sb = new StringBuilder();

    Task.Run()
  5. 现在PerformTaskAction是异步的,你还需要等待它。

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

         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
      }