背线阻止UI线程[闭合]

问题描述 投票:0回答:1
运行时,除了在第二个线程完成之前没有发生时间显示以外,一切都起作用,然后直到关闭表单才停止。
在创建第二个线程时,我错过了什么,以便UI线程将继续更新? tia

private void btnAction_Click(object sender, EventArgs e) { bool Analyze = (cboAnalyzePriceList.SelectedIndex == 0 ? true : false); bool Preview = (cboPreviewOrSave.SelectedIndex == 0 ? true : false); Timer_Start(); (rowCnt, FileMatch, ImportId, srcAnalysis) = ProcessActionButton(Analyze, Preview); PreviewOrSave(Preview); } private (int, bool, string, DataTable) ProcessActionButton(bool Analyze, bool Preview) { SetupProcessForm(Analyze, Preview); Thread thProcess = new Thread(() => { (rowCnt, FileMatch, ImportId, srcAnalysis) = mtdUpdateData.ImportValidateAnalyze(ImportId, PriceListFile, MappingName, Analyze, Preview); } ); thProcess.Start(); (rowCnt, ImportId) = FinalizeProcessForm(rowCnt, FileMatch, srcAnalysis); tbRowCount_Hdr.Text = rowCnt.ToString("N0"); tbImportId_Hdr.Text = ImportId; Timer_Stop(); return (rowCnt, FileMatch, ImportId, srcAnalysis); }

新!改进了!

c# multithreading winforms user-interface
1个回答
-2
投票

新闻合理且可证明的失败理论醒来了,因为在执行OP指出的过程中可能会阻止线程的外观(即使不是)的外观(即使不是),” 这个新理论是基于这样的观察结果:尽管从理论上不影响UI线程的任务将其卸载到另一个线程中,但如果它们足够强烈,则可以垄断CPU资源。这种繁重的需求不会直接阻止UI线程,而是限制了可用的UI资源以平稳或完全更新。您专门强调了ImportValidateAnalyze(...)

方法,因此让我们重点关注这一点。假设我们通过使用tippet所示的

ReadLineAsync()读取一百万行来改善循环。在这种情况下,人们可能会认为循环会屈服于UI以进行更新。但是,我有两个MRE,可以说明我们“知道”的事物可能并不总是是“ so”! 第一个MRE使用适当的配置Progress类。 第二MRE使用外部计时器更新,例如原始OP。

都展示如何使其正常工作。你说得对。它“似乎没有太多要问”!

如果读取一百万行的循环过于紧密,则可以显示示例可以显示“冻结UI”。
我们甚至可以放入一些记录或

DebugWrite
    以查看实际上仍会收到更新请求(即线程本身并没有阻止线程)。
  • 您的最新评论澄清了:
  • “真正的问题”是一个运行10分钟方法的应用程序看起来已经死了!我只想在UI中发布Smething,让用户知道它仍然活着,并且要等待完成。
  • 我们无法访问您的实际代码,但是这种现象似乎有可能导致您所描述的内容。为了进一步探讨这个概念,这里有两个最小示例,这些示例证明了实现更新的成功选择。在这两种情况下,切换复选框都可以通过允许背景循环在而无需限制的情况下进行紧密运行,从而揭示了确定性故障。一旦检查了,UI就不会反应,甚至尝试取消选中复选框不再运行。
  • 小型可复制示例#1(使用
  • Progress
  • 类)
  • 正如Panagiotis Kanavos在评论中所说的那样,一方面,这似乎是
    Progress
  • 类的简单应用。因此,让我们在这方面“做正确的一切”,并设置一个最小的可重现示例,该示例是一百万次,并试图更新进度。下面,摘要不仅显示了如何正确设置此设置,还包括一个故意“破坏”更新机制的选项。
ReadLineAsync()

微型可重现示例#2(使用外部更新计时器,例如OP)

此示例使用与原始海报的方法相似的外部更新计时器,以演示在密集的背景处理中管理UI更新。

public partial class MainForm : Form, IProgress<(TimeSpan, int, int)>
{
    string VeryLargeFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Data", "one-million-guids.txt");
    public MainForm()
    {
        // Make a file with 1 million lines.
        if (!File.Exists(VeryLargeFile)) File.WriteAllText(
            VeryLargeFile,
            string.Join(
                Environment.NewLine,
                Enumerable.Range(0, 1000000)
                .Select(_ => string.Join(
                    " ", 
                    Enumerable.Range(0, 10).Select(_=>$"{Guid.NewGuid()}")))));
        _progress = new Progress<(TimeSpan, int, int)>();
        Debug.Assert(SynchronizationContext.Current != null);
        _progress.ProgressChanged += (sender, e) =>
        {
            Debug.Assert(!InvokeRequired);
            labelElapsed.Text = $@"{e.Item1:hh\:mm\:ss\.f}";
            Text = $"Main Form {e.Item2} of {e.Item3}";

            // Uncomment to show that messages 'are' received but do not update the label.
            // Debug.WriteLine($"{e.Item2} of {e.Item3}");
        };

        InitializeComponent();
        btnAction.Click += btnAction_Click;
    }
    Progress<(TimeSpan, int, int)>? _progress;
    public void Report((TimeSpan, int, int) value) =>
        ((IProgress <(TimeSpan, int, int)>?)_progress)?.Report(value);
    private async void btnAction_Click(object? sender, EventArgs e)
    {
        try
        {
            var cts = new CancellationTokenSource();
            btnAction.Enabled = false;
            labelElapsed.Visible = true;
            await ImportValidateAnalyze(this, cts.Token);
        }
        catch(OperationCanceledException)
        { }
        finally
        {
            btnAction.Enabled = true;
            labelElapsed.Visible = false;
        }
    }
    private async Task ImportValidateAnalyze(IProgress<(TimeSpan, int, int)> progress, CancellationToken token)
    {
        var stopwatch = Stopwatch.StartNew();
        var lastUpdate = 0;

        // "The ImportValidateAnalyze() method may import one million lines from a text file..."
        var count = 0;
        var max = 1000000;
        progress.Report((TimeSpan.Zero, count, max));
        using (StreamReader reader = new StreamReader(VeryLargeFile))
        {
            while (count < max)
            {
                if (await reader.ReadLineAsync(token) is string line)
                {
                    count++;
                    var currentUpdate = (int)(stopwatch.Elapsed.TotalSeconds * 10);
                    if (checkBoxBreakMe.Checked)
                    {
                        // Without throttling.
                        progress.Report((stopwatch.Elapsed, count, max));
                    }
                    else
                    {
                        if (lastUpdate < currentUpdate)
                        {
                            // Throttle updates to 0.1 second intervals.
                            progress.Report((stopwatch.Elapsed, count, max));
                            lastUpdate = currentUpdate;
                        }
                    }
                }
                else break;
            }
        }
        progress.Report((stopwatch.Elapsed, max, max));
    }
}

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.