如果其中一个线程发生故障,是否有任何方法可以停止其他并发线程的执行?我正在一个ASP.NET MVC网站上工作,该网站将大量使用API​​调用。我不是以顺序的方式发送太多的API请求,而是创建线程,每个线程消耗一个API调用。如果任何线程失败,我想杀死其他线程。我怎样才能做到这一点?我使用了Task.WaitAll,但即使一个线程失败,它也允许所有其他线程执行。请帮忙。

更新:
为了模拟实时场景,我创建了一个控制台应用程序。请引用下面的代码。我想使第五个线程失败。在第五个线程失败后,我希望所有其他正在运行的线程停止。

public class Program
{
        static int[] delays = { 3, 2, 10, 4, 5, 6, 7, 8, 9, 1 };
        static int[] ids = new int[10];
        static Task[] tasks = null;
        static CancellationTokenSource tokenSource = new CancellationTokenSource();
        static IList<int> threadsExecuted = new List<int>();

        static void Main(string[] args)
        {
            ids = Enumerable.Range(1, 10).ToArray();

            try
            {
                tasks = ids.Select(id => MyTaks(id)).ToArray();
                Task.WaitAll(tasks);
            }
            catch (Exception exception)
            {
                Console.WriteLine("Exception in Main::\nMessage: " + exception.Message +
                    "StackTrace: " + exception.StackTrace +
                    "InnerException: " + exception.InnerException);
            }

            Console.WriteLine("\n\nThreads executed: " + string.Join(", ", threadsExecuted.OrderBy(id => id).ToArray()));

            Console.WriteLine("\n\n\nExit..");

            Console.Read();
        }

        private static async Task MyTaks(int id)
        {
            var delay = delays[id - 1] * 1000;

            Console.WriteLine("Thread id #" + id + " started with delay " + delay + " seconds.");

            CancellationToken cToken = tokenSource.Token;

            Task task = new Task(() =>
            {
                Thread.Sleep(delay);

                if (id == 5) //Fail
                {
                    Console.WriteLine("Cancelling..");

                    throw new Exception("Thread id #" + id + " failed.");
                }
            }, cToken);

            task.Start();

            await task;

            Console.WriteLine("Thread id #" + id + " executed.");

            threadsExecuted.Add(id);
        }

}

最佳答案



这种方法几乎会破坏服务器的任何可伸缩性。您应该使用异步并发(多个操作),而不是并行并发(多个线程)。您的API代码将使用HttpClient.GetAsync并传递CancellationToken

因此,您的测试代码如下所示:

static void Main(string[] args)
{
  ids = Enumerable.Range(1, 10).ToArray();

  try
  {
    tasks = ids.Select(id => MyTaks(id)).ToArray();
    Task.WaitAll(tasks);
  }
  catch (Exception exception)
  {
    Console.WriteLine("Exception in Main::\nMessage: " + exception.Message +
                "StackTrace: " + exception.StackTrace +
                "InnerException: " + exception.InnerException);
  }

  lock (threadsExecuted)
    Console.WriteLine("\n\nThreads executed: " + string.Join(", ", threadsExecuted.OrderBy(id => id).ToArray()));

  Console.WriteLine("\n\n\nExit..");

  Console.Read();
}

private static async Task MyTaks(int id)
{
  var delay = delays[id - 1] * 1000;

  Console.WriteLine("Task id #" + id + " started with delay " + delay + " seconds.");

  CancellationToken cToken = tokenSource.Token;

  // Production code would use `await httpClient.GetAsync(url, token)` here.
  await Task.Delay(delay, cToken);

  if (id == 5) //Fail
  {
    Console.WriteLine("Cancelling..");
    tokenSource.Cancel();
    throw new Exception("Thread id #" + id + " failed.");
  }

  Console.WriteLine("Thread id #" + id + " executed.");
  lock (threadsExecuted)
    threadsExecuted.Add(id);
}

关于c# - C#:如果一个线程失败,则终止其他线程,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38012732/

10-11 19:13
查看更多