【问题标题】:MultiThreading - For loop doesnt waits on Await多线程 - For 循环不会等待 Await
【发布时间】:2026-01-11 21:10:02
【问题描述】:

我有一个控制台应用程序有两个线程:

    public static async void Thread1()
        {
            for (int i = 0; i < 100; i++)
            {
                Debug.WriteLine("Thread1 " + i);
                await MyFunc();
            }
        }

    public static async void Thread2()
        {
            for (int i = 0; i < 100; i++)
            {
                Debug.WriteLine("Thread2 " + i);
                await MyFunc();
            }
        }
    public static void Main(string[] args)
        {
            MainAsync(args).GetAwaiter().GetResult();
        }
    private static async Task MainAsync(string[] args)
        {

            Console.WriteLine("Before start thread");

            Thread tid1 = new Thread(Thread1);
            Thread tid2 = new Thread(Thread2);

            tid1.Start();

            tid2.Start();
        }

    public static async Task MyFunc()
        {
         //do something
        }

但是,当应用程序运行并终止时,似乎每个线程只运行一次,因为我只在输出中看到以下内容:

 Before start thread
    Thread1 0
    Thread2 0
//some thing from MyFunc

我希望或者宁愿不想在 for 循环之前运行每个线程。在我看来,尽管等待,for 循环仍会继续运行。 如果是,还有什么其他可能的方法。

任何线索都会有所帮助。

【问题讨论】:

  • 为什么 new Thread() vs await Thread1()?或者将 thread1() 和 THread2() 添加到数组并使用 Task.WaitAll()?
  • 我复制了你的代码,我在“调试输出”窗口中看到了 Thread1 0 - Thread1 99Thread2 0 - Thread2 99...所以我没有复制代码。
  • 确实如此。上述两个 cmets 都高度相关。 MyFunc 究竟做了什么?
  • 您介绍的ThreadTask 之间的可互换性让我担心您并不真正了解其中的区别。 "There is no thread"

标签: c# multithreading for-loop locking semaphore


【解决方案1】:

你没有做任何事情来等待线程。主程序将继续执行,直到它返回到 O/S,这将杀死进程和所有子线程。由于您没有做任何其他事情,这几乎会立即发生,从而缩短两个线程的寿命。

如果你想等待线程完成,你可以参考this answer并写一些变体

while (thread1.IsAlive || thread2.IsAlive)
{
    //Do something to wait
}

...在退出之前。

话虽如此,您可能应该使用任务而不是线程,例如

public static async Task Task1()
{
    for (int i = 0; i < 100; i++)
    {
        Debug.WriteLine("Task1 " + i);
        await MyFunc();
    }
}

public static async Task Task2()
{
    for (int i = 0; i < 100; i++)
    {
        Debug.WriteLine("Task2 " + i);
        await MyFunc();
    }
}

然后执行并等待他们两个:

Task.WaitAll
( 
    new[] 
    {
        Task1(), 
        Task2() 
    } 
);

See this code in action on DotNetFiddle

另见What is the difference between tasks and threads?

【讨论】:

    【解决方案2】:

    您似乎对线程和任务的角色有很多困惑,因此最好阅读一下。 Steven Cleary 对此有很好的报道。 "There Is No Thread"

    从 cmets 看来,您的实际意图似乎是并行运行两个 async 任务,然后等待它们都完成。

    如果您想等待两个异步任务并行完成,请确保您的 async 方法实际上返回 Task 然后:

    Task task1 = DoSomethingAsync(); //don't await
    Task task2 = DoSomethingElseAsync(); //don't await
    

    那么你可以异步等待Task.WhenAll

    await Task.WhenAll(task1,task2);
    

    你真的不需要参与Thread

    【讨论】:

      【解决方案3】:

      使用异步 Task 而不是 async void

      private static async Task MainAsync(string[] args)
      {
          Console.WriteLine("Before start thread");
          var task1 = Thread1();
          var task2 = Thread2();
          var taskList = new [] { task1, task2 };
          Task.WaitAll(taskList);
      }
      

      【讨论】:

      • 您的解决方案是否提供与原始解决方案不同的结果?我无法重现他原来的问题。您的代码和他的代码都为我产生了相同的结果。
      • @RufusL 直到我们看到 MyFunc 实际在做什么,我们都处于寒冷之中。
      • 原始代码有竞态条件。应用程序可以在线程工作之前完成。
      • @spender MyFunc 有另一个等待在 Redis 缓存中设置相同的对象。
      • @ShaneRay 等待每个线程所做的是为第一个线程执行 MyFunc 100 次,然后为 Thread2 运行它。我希望它们并行运行,以便在输出中看到例如“Thread1 23, Thread2 15”。