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

如何避免长时间运行的Task受API调用任务干扰?

解决长时间运行Task被API调用干扰的稳定执行方案

核心问题分析

你当前的长时间任务之所以被干扰,主要来自几个关键因素:

  • Console.WriteLine是全局同步操作,大量其他任务调用时会触发锁竞争,导致你的任务被阻塞
  • 固定等待100ms的逻辑没有抵消任务自身执行的耗时,加上系统CPU/线程调度波动,总间隔被拉长
  • 大量API调用任务占用过多系统资源(线程、CPU),增加上下文切换开销

具体解决方案

1. 隔离控制台输出,避免锁竞争

Console.WriteLine内部有全局锁,当其他大量任务也在输出时,你的任务会被阻塞在锁上。改用异步日志队列,让你的任务只负责生产日志,由独立线程处理输出:

// 全局线程安全日志队列
private static readonly ConcurrentQueue<string> _logQueue = new ConcurrentQueue<string>();

// 启动独立的日志输出后台线程
static void InitLogWriter()
{
    new Thread(() =>
    {
        while (true)
        {
            if (_logQueue.TryDequeue(out var message))
            {
                Console.WriteLine(message);
            }
            else
            {
                // 空转时短暂休眠,降低CPU占用
                Thread.Sleep(10);
            }
        }
    }) { IsBackground = true }.Start();
}

// 修改你的长时间任务逻辑
Task.Factory.StartNew(() =>
{
    var step = 0;
    while (true)
    {
        var startTime = DateTime.UtcNow;
        
        // 只入队日志,不直接调用Console.WriteLine
        _logQueue.Enqueue(step.ToString());
        
        step++;
        if (step > MaxStep)
        {
            return;
        }
        
        // 计算剩余等待时间,保证总间隔稳定在100ms
        var elapsedMs = (DateTime.UtcNow - startTime).TotalMilliseconds;
        var waitMs = Math.Max(0, 100 - elapsedMs);
        Thread.Sleep((int)waitMs);
    }
}, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);

2. 提高长时间任务线程的优先级

如果是系统CPU调度导致的干扰,可以给执行该任务的线程设置更高优先级,让操作系统优先调度它:

// 改用Thread直接创建,方便设置优先级
var longRunningThread = new Thread(() =>
{
    var step = 0;
    while (true)
    {
        var startTime = DateTime.UtcNow;
        _logQueue.Enqueue(step.ToString());
        step++;
        if (step > MaxStep)
        {
            return;
        }
        var elapsedMs = (DateTime.UtcNow - startTime).TotalMilliseconds;
        var waitMs = Math.Max(0, 100 - elapsedMs);
        Thread.Sleep((int)waitMs);
    }
})
{
    IsBackground = true,
    // 设置为AboveNormal即可,避免设Highest导致其他任务被饿死
    Priority = ThreadPriority.AboveNormal
};
longRunningThread.Start();

3. 限制API调用任务的并发数

大量API调用任务会占用过多线程资源,增加上下文切换开销。给API调用单独使用限并发的自定义TaskScheduler,避免无限制占用系统资源:

// 自定义限并发TaskScheduler
public class LimitedConcurrencyTaskScheduler : TaskScheduler
{
    private readonly LinkedList<Task> _taskQueue = new LinkedList<Task>();
    private readonly int _maxConcurrency;
    private int _activeThreads = 0;

    public LimitedConcurrencyTaskScheduler(int maxConcurrency)
    {
        if (maxConcurrency < 1)
            throw new ArgumentOutOfRangeException(nameof(maxConcurrency));
        _maxConcurrency = maxConcurrency;
    }

    protected override IEnumerable<Task>? GetScheduledTasks()
    {
        bool lockAcquired = false;
        try
        {
            Monitor.TryEnter(_taskQueue, ref lockAcquired);
            return lockAcquired ? _taskQueue.ToArray() : throw new NotSupportedException();
        }
        finally
        {
            if (lockAcquired) Monitor.Exit(_taskQueue);
        }
    }

    protected override void QueueTask(Task task)
    {
        lock (_taskQueue)
        {
            _taskQueue.AddLast(task);
            if (_activeThreads < _maxConcurrency)
            {
                _activeThreads++;
                ThreadPool.UnsafeQueueUserWorkItem(RunNextTask, null);
            }
        }
    }

    private void RunNextTask(object? state)
    {
        while (true)
        {
            Task? task = null;
            lock (_taskQueue)
            {
                if (_taskQueue.Count == 0)
                {
                    _activeThreads--;
                    break;
                }
                task = _taskQueue.First.Value;
                _taskQueue.RemoveFirst();
            }
            TryExecuteTask(task);
        }
    }

    protected override bool TryExecuteTaskInline(Task task, bool wasPreviouslyQueued)
    {
        if (wasPreviouslyQueued)
            return TryDequeue(task) && TryExecuteTask(task);
        return TryExecuteTask(task);
    }

    protected override bool TryDequeue(Task task)
    {
        lock (_taskQueue) return _taskQueue.Remove(task);
    }

    public override int MaximumConcurrencyLevel => _maxConcurrency;
}

// 使用示例:限制API调用最多用10个并发线程
var apiTaskScheduler = new LimitedConcurrencyTaskScheduler(10);
// 所有API调用任务都使用这个调度器
Task.Factory.StartNew(() => 
{
    // 你的API调用逻辑
}, CancellationToken.None, TaskCreationOptions.None, apiTaskScheduler);

方案组合建议

优先实施步骤1+步骤2,这两个改动最小,且能解决绝大多数锁竞争和调度问题;如果API调用确实占用了过多资源,再加上步骤3限制并发。

内容的提问来源于stack exchange,提问作者Rezo Khurtsilava

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 10:46:20