-2

目前,我有一个包含一堆 id 的 List 字符串 ids、一个以空开头并填充有对象的 List 对象,以及一个函数返回一个对象 getObject(string id),该对象获取给定 id 字符串的对象。有没有一种方法可以轻松地进行线程化,而不必使用 Threading 类连续进行?线程似乎没有办法返回对象,因为它们使用 void 函数。

4

3 回答 3

0

我展示了两种方法来做到这一点,一种是“老式”方式,一种是任务。他们都在一个简单的演示 WinForms 应用程序中(只是因为......)

这是老式的方式(将工作显式提交到线程池)。为此,我创建了一个简单的小类:

public class OldFashionedThread
{
    private readonly List<string> _listOfStrings = new List<string>();

    public IEnumerable<string> ListOfStrings => _listOfStrings;
    public Form1 TheForm { get; set; }

    public void DoWork(object state)
    {
        var strings = new[] {"Some", "strings", "go", "here"};
        foreach (var s in strings)
        {
            _listOfStrings.Add(s);
            Thread.Sleep(500);
        }
        TheForm?.Invoke(new Action(TheForm.AlertAllDone));
    }
}

“AlertAllDone”只是弹出一个消息框说“全部完成”

然后,在我的主要表格上,我有:

   private OldFashionedThread _worker;
   private void StartThreadBtn_Click(object sender, EventArgs e)
   {
       _worker = new OldFashionedThread {TheForm = this};
       ThreadPool.QueueUserWorkItem(_worker.DoWork);
   }

   private void AllDoneBtn_Click(object sender, EventArgs e)
   {
       if (_worker != null)
       {
           var result = string.Join(" ", _worker.ListOfStrings);
           MessageBox.Show(result);
       }
   }

我单击StartThreadBtn按钮,等到 All Done 消息框出现,然后单击AllDoneBtn按钮。

使用任务,我可以做到这一点(直接在表单的代码中):

   private async void AsTaskBtn_Click(object sender, EventArgs e)
   {
       var strings = await GetStringsAsync();
       var result = string.Join(" ", strings);
       MessageBox.Show(result);
   }

   private async Task<IEnumerable<string>> GetStringsAsync()
   {
       return await Task.Run<IEnumerable<string>>(
           () => {
               var listOfStrings = new List<string>();
               var strings = new[] { "Some", "strings", "go", "here" };
               foreach (var s in strings)
               {
                   listOfStrings.Add(s);
                   Thread.Sleep(500);
               }
               return listOfStrings;
           });
   }

await让我等到工作完成(不占用 UI 线程),然后,当它完成时,我醒来并弹出消息框。

于 2018-08-09T20:57:00.203 回答
0

利用:

var task = Task.Run<object>(() => /** your delegate returning an object **/)

然后,您可以使用ResultWait或(最好的、首选的等待)await关键字来处理它。

var returnedObject = await task;

更多关于Task这里:https ://msdn.microsoft.com/en-us/library/system.threading.tasks.task(v=vs.110).aspx

于 2018-08-09T19:45:45.650 回答
0

假设getObject(string id)方法是线程安全的并且是 CPU 密集型的(即它不执行 I/O 操作),那么PLINQ可能是最好的选择。它自动执行分区输入列表的所有魔法,将工作负载分配到所有可用的 CPU 内核,然后将子结果合并回一个结果列表。

List<string> ids = new List<string>(new[] { "a", "b", "c", "d", "e", "f" });

List<Object> objects = ids
    .AsParallel()
    .Select(id => getObject(id))
    .ToList();

如果需要,您还可以使用.WithDegreeOfParallelism(),.WithExecutionMode().WithMergeOptions()扩展方法对其进行配置(但通常使用默认选项可以很好地工作)。

但是如果getObject()方法是 I/O 绑定的,那么使用Task可能是更好的选择。

于 2018-08-09T20:01:52.737 回答