如何在循环内运行多个线程

时间:2016-12-04 23:07:05

标签: c# multithreading winforms

我目前正在执行一项需要花费大量时间的任务。 基本上,我想要做的是在foreach循环中运行多个任务。 我尝试使用Parallel.ForEach来冻结我的UI。我希望能够一次打电话给10个uid。

foreach (var uid in listBox2.Items)
              {
                  if (StopEmail) break;
                  Application.DoEvents();
                  string jsonstring = GetEmails(uid.ToString(), token);
                  if (jsonstring != null)
                  {
                      label6.Text = " Current UID: " + listBox2.Items.IndexOf(uid);
                      dynamic jsonResponse = JsonConvert.DeserializeObject(jsonstring);
                      string idstt = jsonResponse["email"];
                      if (idstt != null)
                      {
                          listBox3.Items.Add(idstt);
                          label4.Text = "Total Emails: " + listBox3.Items.Count.ToString();

                      }
                  }
              }

这是我的Parallel.ForEach代码:

var files = listBox2.Items.Cast<String>().ToList();
Parallel.ForEach(files, uid =>
{
    Application.DoEvents();
    string jsonstring = GetEmails(uid.ToString(), token);
    if (jsonstring != null)
    {
        this.Invoke(new MethodInvoker(delegate()
        {
            label6.Text = " Current UID: " + listBox2.Items.IndexOf(uid);
        }));

        dynamic jsonResponse = JsonConvert.DeserializeObject(jsonstring);
        string idstt = jsonResponse["email"];
        if (idstt != null)
        {
            this.Invoke(new MethodInvoker(delegate()
            {
                listBox3.Items.Add(idstt);
                label4.Text = "Total Emails: " + listBox3.Items.Count.ToString();
            }));
        }
    }
});

2 个答案:

答案 0 :(得分:2)

以下是我采用的方法 - 使用Microsoft的Reactive Framework(NuGet&#34; System.Reactive.Windows.Forms&#34;)。

然后你可以这样做:

package com.example.guestbook;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;

import java.io.IOException;
import java.util.Date;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class GuestbookServlet extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws IOException {
        DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
        Entity entity0 = new Entity("Dummy", "abc");
        entity0.setProperty("created", new Date());
        datastore.put(entity0);
        Entity entity1 = new Entity("Dummy", "xyz");
        entity1.setProperty("created", null);
        datastore.put(entity1);
    }
}

慢速部分位于var uids = listBox2.Item.Cast<String>().ToArray(); var query = from uid in uids.ToObservable() from jsonstring in Observable.Start(() => GetEmails(uid, token)) where jsonstring != null select new { uid, jsonstring }; IDisposable subscription = query .ObserveOn(this) .Subscribe(x => { label6.Text = " Current UID: " + listBox2.Items.IndexOf(x.uid); dynamic jsonResponse = JsonConvert.DeserializeObject(x.jsonstring); string idstt = jsonResponse["email"]; if (idstt != null) { listBox3.Items.Add(idstt); label4.Text = "Total Emails: " + listBox3.Items.Count.ToString(); } }); 调用中,因此GetEmails处理得很好。

query调用会将代码编组回UI线程,因此不需要调用.ObserveOn(this)次调用。

最后,为了尽早结束计算,只需调用.Invoke

答案 1 :(得分:0)

Parallel.ForEach换入Task.Run来电:

var files = listBox2.Items.Cast<String>().ToList();
Task task = Task.Run( () => {

    Parallel.ForEach( files, uid =>
    {
        // remove the `Application.DoEvents()` call, it is unnecessary
        // ...
    }

} );

相反,从ForEach方法返回数据而不是调用.Invoke可能是更好的设计,这样您就可以使用await并在一次转发时更新UI ForEach已完成 - 但这取决于循环的性质和所需的用户体验。