Task.WaitAll()不能按预期工作 [英] Task.WaitAll() not working as expected

查看:627
本文介绍了Task.WaitAll()不能按预期工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想弄清楚如何使用Task类工作。在过去,我一直使用的常规Thread类的,但我试图抓住所有的异步编程的...

作为一个例子,我创建了具有所有code主要WinForms应用程序。
有关code我的问题是:

  //相关代表
公共委托无效MethodAction(INT NUM);
公共委托无效MethodConversion();
公共委托无效OnCompletionAction(字符串completiontext);//按钮用户presses
私人无效button4_Click(对象发件人,EventArgs的发送)
{
    richTextBox1.Clear();
    sw.Reset();
    sw.Start();
    Sync.RunAsync3(calcSim);
}//它通过添加睡眠模拟计算的方法
//输入参数threadlength只是让线程需要比别人更长
//因为我多线程,我要调用Windows的RichTextbox控件写作code
私人无效calcSim(INT threadlength)
{
    字符串threadname = Thread.CurrentThread.Name;
    的for(int i = 0;我小于10;我++)//线程计算应采取3S
    {
        Thread.sleep代码(300 + threadlength);
        richTextBox1.Invoke((MethodConversion)(()=>
                            {
                                richTextBox1.AppendText(的String.Format(主题:{0} \\ tVersion:{1} \\ n,threadname,第(i + 1)的ToString()));
                            }));
    }
}//包含不同的加工方法类
公共静态类同步
{
    公共静态事件OnCompletionAction OnProcCompletion;    公共静态无效RunAsync3(MethodAction DOM)
    {
        任务[] T =新任务[4];
        的for(int i = 0;我4;;我++)
        {
            T [i] = Task.Factory.StartNew((动作)(()=> {DOM(50 * I);}));
        }
        Task.WaitAll(T);
        如果(OnProcCompletion!= NULL)OnProcCompletion(RunSync方法完成了);
    }
}

问题在于内Task.WaitAll(T)...出于某种原因,我想不通,就在该行完全阻断,并不再响应。如果我省略线,形式获取实时更新,执行时间约3秒。

我的问题是:为什么不是Task.WaitAll()释放它并允许code的剩余部分执行之前拦截3秒UI线程

我知道它应该被阻塞UI一段时间(直到计算所有线程),但它会阻止完整的App不休。这似乎是永远的守候?

修改

我一直在建议使用的,而不是为WaitAll WhenAll。我已经改写RunAsync3如下:

 公共静态无效RunAsync3(MethodAction DOM)
{
    任务[] T =新任务[4];
    的for(int i = 0;我4;;我++)
    {
        T [i] = Task.Factory.StartNew((动作)(()=> {DOM(50 * I);}));
    }
    //Task.WaitAll(t); - >僵局
    Task.WaitAll(新任务[] {Task.WhenAll(T)});
    如果(OnProcCompletion!= NULL)OnProcCompletion(RunSync方法完成了);
}

但是这仍然是越来越僵持......?我可能会使用不正确WhenAll?

编辑2

由于每个人都声称我是阻塞UI线程是正确的,我决定试试这个法子:通过运行一个新的线程的UI线程内我调用线程(所以现在阻止将在我的线程发生UI,而不是线)。这工作,但显然不是这样做的最佳方式!

 私人无效button4_Click(对象发件人,EventArgs的发送)
{
    线程t =新主题(新的ThreadStart(()=>
    {
        richTextBox1.Invoke((MethodConversion)(()=> richTextBox1.Clear()));
        sw.Reset();
        sw.Start();
        Sync.RunAsync3(calcSim);
    }));
    t.Start();
}
公共静态无效RunAsync3(MethodAction DOM)
{
    任务[] T =新任务[4];
    的for(int i = 0;我4;;我++)
    {
        T [i] = Task.Factory.StartNew((动作)(()=> {DOM(50 * I);}));
    }
    Task.WaitAll(T);
   //Task.WaitAll(new任务[] {Task.WhenAll(T)});
   如果(OnProcCompletion!= NULL)OnProcCompletion(RunSync方法完成了);
}


解决方案

您会导致死锁。

在UI线程等待完成4个任务。

在另一方面,这4个任务,运行 calcSim 正在尝试调用code UI线程 - >死锁

您应该使用 Task.WhenAll()来代替。该方法将返回当所有的任务都完成完成将标志着一个新的任务。如果您等待的任务,您的UI线程将被释放,所以 calcSim 将能够调用在UI线程上code,避免死锁。

更新

您正在使用它错了。你还在使用为WaitAll ,这是一个阻塞调用。你应该的 WhenAll 替换的吧。

 等待Task.WhenAll(T);

从<一个href=\"http://msdn.microsoft.com/en-us/library/system.threading.tasks.task.whenall%28v=vs.110%29.aspx\">documentation:


  

创建一个任务,当所有的供应任务,有将完成
  完成。


通过调用等待的结果,你的UI线程将是免费的 - 直到所有的4个任务完成。当这种情况发生时,你的 RunAsync3 方法将恢复。

I'm trying to figure out how to work with the Task class. In the past I have always used the regular Thread class, but I'm trying to grasp all of the asynchronous programming...

As an example, I created a main Winforms application that has all the code. The relevant code for my problem is:

//Relevant delegates
public delegate void MethodAction(int num);
public delegate void MethodConversion();
public delegate void OnCompletionAction(string completiontext);

//Button user presses
private void button4_Click(object sender, EventArgs e)
{
    richTextBox1.Clear();
    sw.Reset();
    sw.Start();
    Sync.RunAsync3(calcSim);
}

//The method that simulates a calculation by adding a sleep
//the input param threadlength is just to allow threads to take longer than others
//since I'm multithreading, I have to invoke the writing code on the windows RichTextbox control
private void calcSim(int threadlength)
{
    string threadname = Thread.CurrentThread.Name;
    for (int i = 0; i < 10; i++) //Thread calc should take 3s
    {
        Thread.Sleep(300 + threadlength);
        richTextBox1.Invoke((MethodConversion)(() =>
                            { 
                                richTextBox1.AppendText(string.Format("Thread: {0}\tVersion: {1}\n", threadname, (i + 1).ToString())); 
                            }));
    }
}

//Class that contains the different processing methods
public static class Sync
{
    public static event OnCompletionAction OnProcCompletion;

    public static void RunAsync3(MethodAction doM)
    {
        Task[] t = new Task[4];
        for(int i = 0; i < 4; i++)
        {
            t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
        }
        Task.WaitAll(t);
        if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
    }
}

The problem lies within Task.WaitAll(t)... For some reason, which I can't figure out, it completely blocks on that line and doesn't respond anymore. If I omit that line, the form gets updated in realtime and the execution take about 3 seconds.

My question is: why isn't Task.WaitAll() blocking the UI thread for 3 seconds before releasing it and allowing the rest of the code to execute?

I know it should be blocking the UI for some time (until all threads are calculated), but it blocks the complete app endlessly. It seems to be waiting forever?

EDIT

I've been suggested to use WhenAll instead of WaitAll. I have rewritten RunAsync3 as follows:

public static void RunAsync3(MethodAction doM)
{
    Task[] t = new Task[4];
    for(int i = 0; i < 4; i++)
    {
        t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
    }
    //Task.WaitAll(t); -> deadlock
    Task.WaitAll(new Task [] { Task.WhenAll(t) });
    if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}

But this is still getting deadlocked...? I might be using the WhenAll incorrectly?

EDIT 2

Because everybody claiming that I was blocking the UI thread were right, I decided to try this another way: by running a new thread as my calling thread inside the UI thread (so that blocking now would occur on my thread instead of UI thread). This works, but is obviously not the best way to do this!

private void button4_Click(object sender, EventArgs e)
{
    Thread t = new Thread(new ThreadStart(() =>
    {
        richTextBox1.Invoke((MethodConversion)(() => richTextBox1.Clear()));
        sw.Reset();
        sw.Start();
        Sync.RunAsync3(calcSim);
    }));
    t.Start();
}
public static void RunAsync3(MethodAction doM)
{
    Task[] t = new Task[4];
    for(int i = 0; i < 4; i++)
    {
        t[i] = Task.Factory.StartNew((Action)(() => { doM(50 * i); }));
    }
    Task.WaitAll(t);
   //Task.WaitAll(new Task [] { Task.WhenAll(t) });
   if (OnProcCompletion != null) OnProcCompletion("RunSync method finished");
}

解决方案

You're causing a deadlock.

The UI thread is waiting for 4 tasks to be completed.

On the other hand, those 4 tasks, running calcSim are trying to invoke code on the UI thread -> Deadlock.

You should be using Task.WhenAll() instead. That method will return a new task that will be marked as completed when all your for tasks have completed. If you await that task, your UI thread will be freed, and so calcSim will be able to invoke code on the UI thread, avoiding a deadlock.

Update

You're using it wrong. You're still using WaitAll, which is a blocking call. You should replace it with WhenAll.

await Task.WhenAll(t);

From the documentation:

Creates a task that will complete when all of the supplied tasks have completed.

By calling await on the result, your UI thread will be free - until all 4 tasks complete. When that happens, your RunAsync3 method will resume.

这篇关于Task.WaitAll()不能按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆