简体   繁体   English

异步调用多个方法

[英]Calling multiple methods asynchronously

Is there a way to call multiple methods at the same time? 有没有办法同时调用多个方法? I have a winforms app that loads an incredible amount of data upon loading: 我有一个winforms应用程序,加载时加载了大量的数据:

private void form1_Load(object sender, EventArgs e)
{
    LoadValues1();
    LoadValues2();
    LoadValues3();
    LoadValues4();
    LoadValues5();
    LoadValues6();
    LoadValues7();
    LoadValues8();
}

These methods retrieve data and populate DevExpress LookUpEdits (similar to windows dropdownlists), so they all look like this: 这些方法检索数据并填充DevExpress LookUpEdits(类似于windows下拉列表),因此它们看起来像这样:

DBContext dbContext = new DBContext();
ObservableCollection<string> values1 = 
    new ObservableCollection<string>((from i in dbContext.Items
                                      where i.Value1 != null
                                      && i.Value1.Length > 0
                                      orderby i.Value1
                                      select i.Value1).Distinct());

lookupValues1.Properties.DataSource = descModelYear;
DevExpress.XtraEditors.Controls.LookUpColumnInfoCollection colInfo = lookupValues1.Properties.Columns;
colInfo.Clear();
colInfo.Add(new DevExpress.XtraEditors.Controls.LookUpColumnInfo("Column"));
colInfo[0].Caption = "Values 1";

and some of these methods take a while to complete, yet none of them are dependent on one another, so I thought I could do them all at the same time: 其中一些方法需要一段时间才能完成,但是它们都没有相互依赖,所以我想我可以同时完成所有这些:

Task.Factory.StartNew(() => LoadValues1());
Task.Factory.StartNew(() => LoadValues2());
etc.

but I keep getting an error when the 2nd task is run, saying a control can't be accessed from a different thread than what it was created on. 但是当第二个任务运行时我一直收到一个错误,说无法从与创建它不同的线程访问控件。

Any help is appreciated! 任何帮助表示赞赏!

As others have pointed out you need to ensure that when accessing UI elements you need to make sure that you do it on the proper read. 正如其他人指出的那样,您需要确保在访问UI元素时,您需要确保在正确阅读时执行此操作。 This is easy to do using the Task Parallelism Library like so: 使用Task Parallelism Library很容易做到这样:

private TaskScheduler m_TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();

Once you have the TaskScheduler you can schedule your tasks to run on the UI thread like this: 拥有TaskScheduler后,您可以安排在UI线程上运行的任务,如下所示:

Task.Factory.StartNew(() => 
{
     LoadValues1();
}, CancellationToken.None, TaskCreationOptions.None, m_TaskScheduler);

The caveat here is that running all of your tasks on the UI thread might still lock things up on you. 需要注意的是,在UI线程上运行所有任务可能仍会锁定您。 I would recommend that you create some sort of class or set of collections that you can populate the relevant information in to and then once all the data is there for you to call another method on the UI thread that just binds your controls to the data or does whatever UI specific actions you need. 我建议您创建一些类或一组集合,您可以填充相关信息,然后一旦所有数据都在那里,您可以在UI线程上调用另一个方法,将控件绑定到数据或执行您需要的任何UI特定操作。

When manipulating UI controls, you must be do so on the same thread that created the control. 在操作UI控件时,必须在创建控件的同一线程上执行此操作。 In this case, you should just run those methods that modify the UI synchronously. 在这种情况下,您应该只运行那些同步修改UI的方法。 If all of the methods modify the UI, you should split the work so that only the code that modifies the UI is invoked on the UI thread. 如果所有的方法修改UI,你应该让只有修改UI代码在UI线程调用拆分工作。

In general, you can use InvokeRequired to check whether you are on the right thread, and Invoke to run a method on the UI thread. 通常,您可以使用InvokeRequired来检查您是否在正确的线程上,并使用Invoke在UI线程上运行方法。

You should separate out your logic in distinct units and try to get your UI logic in one place. 您应该以不同的单位分离逻辑,并尝试将UI逻辑放在一个位置。

//private fields
private readonly DBContext _dbContext = new DBContext();

private Task<ICollection<string>> GetValues1()
{
    return Task.Run(() =>
            {
                return (from i in _dbContext.Items
                        where i.Value1 != null
                        && i.Value1.Length > 0
                        orderby i.Value1
                        select i.Value1)
                        .Distinct()
                        .ToList();
             };
}

private void LoadUIElements1(ICollection<string> values)
{
    var observableValues = new ObservableCollection<string>(values);

    lookupValues1.Properties.DataSource = descModelYear;
    DevExpress.XtraEditors.Controls.LookUpColumnInfoCollection colInfo = lookupValues1.Properties.Columns;
    colInfo.Clear();
    colInfo.Add(new DevExpress.XtraEditors.Controls.LookUpColumnInfo("Column"));
    colInfo[0].Caption = "Values 1";
}

private async void form1_Load(object sender, EventArgs e)
{
    var tasks = new List<Task>();

    // Start each UI task so they will complete independently.
    var uiTask1 =  GetValues1()
          .ContinueWith(t =>
                LoadUIElements1(t.Result),
                CancellationToken.None,
                TaskCreationOptions.None,
                TaskScheduler.FromCurrentSynchronizationContext());
    tasks.Add(uiTask1);

    // Wait for all the tasks to complete
    Task.WaitAll(tasks.ToArray());
    tasks.Clear();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM