线程中止异常与 await

3
我遇到了一个奇怪的错误。 我有大约100个长时间运行的任务,我想同时运行其中的10个。
我在这里找到了与我的需求非常相似的内容:http://msdn.microsoft.com/en-us/library/hh873173%28v=vs.110%29.aspx 在节流部分。
这里是简化后的C#代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    public class Program
    {
        static void Main(string[] args)
        {
            Test();
        }

        public static async void Test()
        {
            var range = Enumerable.Range(1, 100).ToList();

            const int CONCURRENCY_LEVEL = 10;
            int nextIndex = 0;
            var matrixTasks = new List<Task>();

            while (nextIndex < CONCURRENCY_LEVEL && nextIndex < range.Count())
            {
                int index = nextIndex;
                matrixTasks.Add(Task.Factory.StartNew(() => ComputePieceOfMatrix()));
                nextIndex++;
            }

            while (matrixTasks.Count > 0)
            {
                try
                {
                    var imageTask = await Task.WhenAny(matrixTasks);
                    matrixTasks.Remove(imageTask);
                }
                catch (Exception e)
                {
                    Console.Write(1);
                    throw;
                }

                if (nextIndex < range.Count())
                {
                    int index = nextIndex;
                    matrixTasks.Add(Task.Factory.StartNew(() => ComputePieceOfMatrix()));
                    nextIndex++;
                }
            }

            await Task.WhenAll(matrixTasks); 
        }

        private static void ComputePieceOfMatrix()
        {
            try
            {
                for (int j = 0; j < 10000000000; j++) ;
            }
            catch (Exception e)
            {
                Console.Write(2);
                throw;
            }
        }
    }
}

当从单元测试中运行时,ComputePieceOfMatrix方法会出现ThreadAbortException异常。

你有任何想法吗?

编辑:

根据评论的建议,我尝试了以下操作:

static void Main(string[] args)
{
    Run();
}

private static async void Run()
{
    await Test();
}

public static async Task Test()
{
    var range = Enumerable.Range(1, 100).ToList();

但这完全相同。


等等,什么?async void?我想你是指async Task - Steven Liekens
Resharper 告诉我如果我不使用 Task,那么返回它是没有用的。我会尝试一下。 - Guillaume Philipp
我猜测你的主线程在Test完成之前就退出了,应用程序退出之前现有的线程被中止。 - Lee
我已经编辑了我的问题。那不起作用...谢谢! - Guillaume Philipp
3个回答

2

1.您的代码引发了异常

try
{
    for (int j = 0; j < 10000000000; j++) ;
}
catch (Exception e)
{
    Console.Write(2);
    throw;
}

由于10000000000是长整型,而j计数器是整型,因此出现了简单的OverflowException。

2.在子线程运行完成之前,您的主线程已经退出。很可能是由于运行时关闭了线程,导致ThreadAbortException。

3.正确的方法是直接调用Test(),不需要加上await,同时也不需要在Task.WhenAny前面加上await。


哇...是的,你在测试代码方面是正确的。但在我的实际代码中,原因并不相同...我实际上正在调用一个Web服务。现在我必须找到一个像我的真实代码一样崩溃的小代码,但没有像那样愚蠢的错误...谢谢! - Guillaume Philipp
没错,var imageTask = await Task.WhenAny(matrixTasks); 这里不应该使用await。在这里也不要使用await,因为它会打断你的执行流程。 - Regfor
必须要分解开,否则我会有超过10个任务同时运行。 - Guillaume Philipp

1
Test()的返回类型更改为Task,然后在程序到达结尾之前等待该Task完成。
static void Main(string[] args)
{
    Test().Wait();
}

public static async Task Test()
{
    // ...
}

0

我会将你的测试从void更改为Task返回类型,并在主方法中使用Test();

Task t = Test();
t.Wait();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接