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

执行Regex时CancellationTokenSource失效问题求助

问题分析与解决方案

你猜的没错!你的情况和那个主题里的问题本质完全一致——你的代码(包括深层的Regex逻辑)根本没有监听CancellationToken的取消请求,所以哪怕你调用了CancelAfter,也没法打断那个陷入死循环的Regex匹配过程。

先拆解下你两种实现里的具体问题:

第一种实现的核心问题

  • 你用了task.RunSynchronously(),这会直接阻塞当前线程同步执行任务,后面的task.Wait(1000)完全是多余的——要么任务已经跑完,要么已经卡在Regex死循环里了,等待超时后调用Cancel()也毫无意义,因为任务里根本没检查令牌。
  • 日志部分的异步方法没加await,会导致文件读写冲突,日志内容也可能乱序或丢失。

第二种实现的核心问题

  • 虽然用了await Task.Run(..., token),但TryToCreateCodeFile以及更深层的Regex.Matches()完全没理会这个令牌。TaskCanceledException只会在任务主动检查并响应令牌时才会抛出,否则任务会一直卡在死循环里,永远不会触发异常。
  • 同样,日志的异步方法没加await,存在资源竞争问题。

可行的解决方案

短期应急:强制终止超时任务(有风险)

因为Regex.Matches()的死循环是在托管线程内部阻塞,没法通过常规的令牌检查中断,所以我们可以用Task.WhenAny结合线程中断的方式强制终止(注意:这种方式比较粗暴,可能导致资源泄漏,仅作为临时方案):

public static async Task<CodeFile> CreateCodeFile(string fileName)
{
    var fileInfo = new FileInfo(fileName);
    foreach (var codeFileFactory in CodeFileFactories)
    {
        using var cts = new CancellationTokenSource();
        cts.CancelAfter(1000);
        
        Task<CodeFile> task = null;
        Thread taskThread = null;
        
        // 启动任务并记录执行它的线程
        task = Task.Run(() =>
        {
            taskThread = Thread.CurrentThread;
            return TryToCreateCodeFile(codeFileFactory, fileInfo);
        }, cts.Token);

        // 等待任务完成或超时
        var completedTask = await Task.WhenAny(task, Task.Delay(Timeout.Infinite, cts.Token));
        if (completedTask == task)
        {
            // 任务正常完成,返回结果
            var result = await task;
            if (result != null) return result;
        }
        else
        {
            // 超时,尝试中断执行线程
            if (taskThread != null && taskThread.IsAlive)
            {
                try
                {
                    taskThread.Interrupt();
                }
                catch (ThreadStateException)
                {
                    // 线程已结束,忽略异常
                }
            }
            // 修正日志写法:必须await异步方法
            var existingLog = await File.ReadAllTextAsync("FailedLog.txt");
            await File.WriteAllTextAsync("FailedLog.txt", $"{existingLog}\r\n{fileName}");
        }
    }
    return null;
}

长期根治:修复正则表达式

线程中断只是权宜之计,最稳妥的方式还是优化你的正则表达式,消除灾难性回溯导致的死循环:

  • 避免嵌套的贪婪量词(比如(a+)+)
  • 给正则添加明确的边界条件,减少匹配时的回溯次数
  • 可以用RegexOptions.Compiled提前编译正则,同时在测试时用Regex.Matches的超时重载(.NET 5+支持):
    // .NET 5+ 支持的带超时的Matches方法
    var matches = regex.Matches(content, matchTimeout: TimeSpan.FromSeconds(1));
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 00:42:32