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

搜索启动后UI控件3-6秒无响应的问题排查求助

搜索启动后UI控件3-6秒无响应的问题排查求助

大家好,我最近做了一个文件内容搜索工具,遇到了一个奇怪的UI卡顿问题,想请各位帮忙分析下:

当点击启动搜索按钮后,前3-6秒内界面上的按钮(比如暂停、取消)完全不响应鼠标操作,但程序并没有真的冻结——后台的搜索逻辑还在正常运行,过了这段时间后所有控件又能正常响应了。

以下是按钮点击事件的核心代码:

private async void BtnStart_Click(object sender, EventArgs e)
{
    if (isSearching) return;
    ClearLog();

    string path = txtFolderPath.Text.Trim();
    string keywordInput = txtKeyword.Text.Trim();
    string extension = comboExtensions.SelectedItem?.ToString();
    bool includeSub = chkSubfolders.Checked;
    bool showErrors = chkShowErrors.Checked;

    if (string.IsNullOrWhiteSpace(path) || string.IsNullOrWhiteSpace(keywordInput) || !Directory.Exists(path))
    {
        Log("Invalid path or keyword.", Color.Red);
        return;
    }

    string[] rawTerms = keywordInput.Split(new[] { "⬌" }, StringSplitOptions.None);
    var keywordList = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
    foreach (string raw in rawTerms)
    {
        string term = raw.Trim();
        if (!string.IsNullOrEmpty(term))
            keywordList.Add(term);
    }

    if (keywordList.Count == 0)
    {
        Log("No valid search terms found.", Color.Red);
        return;
    }

    isSearching = true;
    cts = new CancellationTokenSource();
    startTime = DateTime.Now;
    elapsedTimer.Start();

    btnStart.Enabled = false;
    btnPauseResume.Enabled = true;
    btnCancel.Enabled = true;

    Log("Search started...", Color.Yellow);
    Log($"Path: {path}", Color.Gray);
    Log($"Extensions: {extension}", Color.Gray);
    Log($"Terms: {string.Join(", ", keywordList)}", Color.Gray);
    Log($"Subfolders: {(includeSub ? "Yes" : "No")}, Errors: {(showErrors ? "Shown" : "Hidden")}", Color.Gray);

    totalFiles = 0;
    scannedFiles = 0;
    matchCount = 0;

    // Offload file enumeration to a background thread
    List<string> files = await Task.Run(() => GetFiles(path, extension, includeSub));
    totalFiles = files.Count;
    lblTotalFiles.Text = $"Total files: {totalFiles}";

    await Task.Run(() =>
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        try
        {
            var options = new ParallelOptions
            {
                CancellationToken = cts.Token,
                MaxDegreeOfParallelism = Math.Max(1, Environment.ProcessorCount / 2)
            };

            Parallel.ForEach(files, options, (file) =>
            {
                pauseEvent.Wait();
                if (cts.Token.IsCancellationRequested || !isSearching) return;

                Interlocked.Increment(ref scannedFiles);

                BeginInvoke((Action)(() =>
                {
                    if (!isSearching) return;
                    lblScannedFiles.Text = $"Scanned: {scannedFiles}/{totalFiles}";
                    if (scannedFiles > 0)
                    {
                        averageTimePerFile = stopwatch.Elapsed.TotalSeconds / scannedFiles;
                        double estimatedRemainingTime = averageTimePerFile * (totalFiles - scannedFiles);
                        lblEstimateTime.Text = $"Estimate: {estimatedRemainingTime:F0}s";
                    }
                }));

                try
                {
                    string content = File.ReadAllText(file);
                    int localMatches = 0;
                    foreach (string term in keywordList)
                    {
                        int index = 0;
                        while ((index = content.IndexOf(term, index, StringComparison.OrdinalIgnoreCase)) != -1)
                        {
                            localMatches++;
                            index += term.Length;
                        }
                    }

                    if (localMatches > 0)
                    {
                        Interlocked.Add(ref matchCount, localMatches);
                        BeginInvoke((Action)(() =>
                        {
                            if (!isSearching) return;
                            Log($"✔ MATCH: {file}", Color.Green);
                        }));
                    }
                }
                catch (Exception ex)
                {
                    if (showErrors)
                    {
                        BeginInvoke((Action)(() =>
                        {
                            if (!isSearching) return;
                            Log($"⚠ ERROR: {file} => {ex.Message}", Color.Red);
                        }));
                    }
                }
            });
        }
        catch (OperationCanceledException)
        {
            if (isCancel)
            {
                BeginInvoke((Action)(() =>
                {
                    Log("Search cancelled during operation.", Color.DeepSkyBlue);
                    btnStart.Enabled = true;
                }));
                isCancel = false;
            }
        }

        stopwatch.Stop();

        if (!cts.Token.IsCancellationRequested)
        {
            BeginInvoke((Action)(() =>
            {
                isSearching = false;
                elapsedTimer.Stop();
                lblElapsedTime.Text = $"Elapsed: {(DateTime.Now - startTime).TotalSeconds:F0}s";
                lblEstimateTime.Text = "Estimate: Done";
                Log("", Color.Black);
                Log($"Search complete. Matches: {matchCount} at {DateTime.Now:HH:mm:ss}", Color.Cyan);
                btnStart.Enabled = true;
                btnPauseResume.Enabled = false;
                btnCancel.Enabled = false;
            }));
        }
    });
}

我已经尝试过优化UI更新频率,比如改成每扫描100个文件才触发一次BeginInvoke更新进度:

if (scannedFiles % 100 == 0)
{
    BeginInvoke((Action)(() =>
    {
        lblScannedFiles.Text = $"Scanned: {scannedFiles}/{totalFiles}";
        averageTimePerFile = stopwatch.Elapsed.TotalSeconds / scannedFiles;
        double estimatedRemainingTime = averageTimePerFile * (totalFiles - scannedFiles);
        lblEstimateTime.Text = $"Estimate: {estimatedRemainingTime:F0}s";
    }));
}

但这个改动并没有解决前几秒的UI无响应问题。我也怀疑过是不是pauseEvent或者BeginInvoke的使用有问题,但奇怪的是只有搜索启动的前几秒会卡顿,之后全程都很流畅,控件响应也正常。

有没有大佬能帮我分析下可能的原因,或者给点排查方向?谢谢大家!

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 11:28:11