You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多线程环境下按入队顺序打印队列内容的实现疑问

问题解答

你的代码无法实现严格按入队顺序打印所有元素的需求,仅能保证相同User.Id的任务串行执行,但不同Id的任务之间没有顺序约束,会出现乱序输出。

原因分析

  1. 任务调度无顺序性:在ReadFromQueue方法中,你一次性将队列所有元素出队,然后为每个元素创建独立的Task交由线程池调度。线程池的任务执行顺序完全由系统资源分配决定,不遵循任务创建的先后顺序,因此不同Id的元素(比如第一个{1, "Single"}和第二个{2, "Single"})谁先执行是随机的。
  2. 同步范围有限:你使用的SemaphoreSlim仅针对相同User.Id的任务做了串行控制,确保同一个Id的任务按入队顺序执行,但不同Id的任务之间没有任何同步机制,无法保证整体的入队顺序。

改进方案

根据你的需求,提供两种可行的改进方向:

方向一:严格按入队顺序执行任务(串行执行任务链)

如果要求PrintInOrder方法必须严格按入队顺序依次执行(前一个元素处理完成后再处理下一个),可以通过构建顺序任务链实现:

修改ReadFromQueue方法为异步版本:

internal async Task ReadFromQueueAsync()
{
    while (usersQueue.Count > 0)
    {
        var user = usersQueue.Dequeue();
        // 等待当前任务执行完成后,再处理下一个元素
        await Task.Run(() => PrintInOrder(user));
    }
}

同时修改Main方法调用:

public static async Task Main()
{
    var printUsersQueueInOrderMutlithreaded = new PrintUsersQueueInOrderMutlithreaded();
    printUsersQueueInOrderMutlithreaded.PopulateQueue();
    await printUsersQueueInOrderMutlithreaded.ReadFromQueueAsync();

    Console.ReadLine();
}

这种方式保证了任务的执行顺序完全匹配入队顺序,每个任务完成后才会启动下一个。

方向二:并行处理任务,严格按入队顺序输出结果

如果允许任务并行执行(比如PrintInOrder内有耗时操作),但要求输出结果严格按入队顺序,可以通过为元素添加序号+并行处理后排序输出实现:

  1. 为User类添加序号属性:
internal class User
{
    public int Id { get; set; }
    public string MaritalStatus { get; set; }
    public int SequenceNumber { get; set; } // 新增序号属性

    public override string ToString()
    {
        return $"Thread id {Thread.CurrentThread.ManagedThreadId,2}" +
            $" User id {Id,2} Marital status {MaritalStatus,10}";
    }
}
  1. 修改PopulateQueue方法为元素赋值序号:
internal void PopulateQueue()
{
    int sequence = 0;
    usersQueue.Enqueue(new User() { Id = 1, MaritalStatus = "Single", SequenceNumber = sequence++ });
    usersQueue.Enqueue(new User() { Id = 2, MaritalStatus = "Single", SequenceNumber = sequence++ });
    usersQueue.Enqueue(new User() { Id = 1, MaritalStatus = "Married", SequenceNumber = sequence++ });
    usersQueue.Enqueue(new User() { Id = 1, MaritalStatus = "Divorced", SequenceNumber = sequence++ });
    usersQueue.Enqueue(new User() { Id = 2, MaritalStatus = "Married", SequenceNumber = sequence++ });
    usersQueue.Enqueue(new User() { Id = 2, MaritalStatus = "Divorced", SequenceNumber = sequence++ });
    usersQueue.Enqueue(new User() { Id = 1, MaritalStatus = "Widow", SequenceNumber = sequence++ });
    usersQueue.Enqueue(new User() { Id = 2, MaritalStatus = "Widow", SequenceNumber = sequence++ });
}
  1. 修改ReadFromQueue方法实现并行处理+顺序输出:
internal async Task ReadFromQueueAsync()
{
    var tasks = new List<Task<(int Sequence, string Output)>>();
    
    while (usersQueue.Count > 0)
    {
        var user = usersQueue.Dequeue();
        // 并行执行任务,保存序号和输出结果
        tasks.Add(Task.Run(() => 
        {
            // 这里可以执行耗时的处理逻辑
            return (user.SequenceNumber, user.ToString());
        }));
    }

    // 等待所有任务完成
    var results = await Task.WhenAll(tasks);
    // 按序号排序后输出,保证顺序
    foreach (var result in results.OrderBy(r => r.Sequence))
    {
        Console.WriteLine(result.Output);
    }
}

这种方式既利用了多线程并行处理提升效率,又能保证最终输出严格匹配入队顺序。


内容的提问来源于stack exchange,提问作者Lior Dadon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 13:47:09