【问题标题】:After opening Task.Factory.StartNew in second time all my UI freezing在第二次打开 Task.Factory.StartNew 后,我所有的 UI 都冻结了
【发布时间】:2014-04-21 11:24:00
【问题描述】:

我有接收文件列表并在单个/单独线程中工作的函数:

public void DoWork(params...)
{
    _filesInProcess = 0;
    _filesFinished = 0;
    _tokenSource = new CancellationTokenSource();
    var token = _tokenSource.Token;
    Task.Factory.StartNew(() =>
    {
        try
        {
            Parallel.ForEach(_indexedSource,
                new ParallelOptions
                {
                    MaxDegreeOfParallelism = parallelThreads //limit number of parallel threads 
                },
                file =>
                {
                    if (token.IsCancellationRequested)
                        return;
                    //do work...
                });
        }
        catch (Exception)
        { }

    }, _tokenSource.Token).ContinueWith(
            t =>
            {
                //finish...
                 if (OnFinishWorkEventHandler != null)
                     OnFinishWorkEventHandler(this, EventArgs.Empty);
            }
        , TaskScheduler.FromCurrentSynchronizationContext() //to ContinueWith (update UI) from UI thread
        );
}

我添加了在循环中运行此命令的选项,在此函数完成后从主窗体中,如果我需要另一个循环,我会再次调用此函数,但在第二次这冻结了我所有的 UI,我无法找到为什么

这就是我调用函数的方式:

private void StartJob()
{
    string[] files = GetlFiles().ToArray();
    Job job = new Job(files);
    timerStatus.Enabled = true;
    job.OnStartPlayEventHandler += job_OnStartPlayEventHandler;
    job.OnFinishPlayEventHandler += job_OnFinishPlayEventHandler;
    job.OnFinishWorkEventHandler += job_OnFinishWorkEventHandler;
    job.StartTimerEventHandler += job_StartTimerEventHandler;
    job.StopTimerEventHandler += job_StopTimerEventHandler;
    job.DoWork(
                NetworkAdapter.SelectedAdapter.PacketDevice,
                ReadSpeed(),
                PlayOption.Regular,
                ChecksumFixer.FixBadChecksum,
                ReadParallelThreads(PlayState.Single),
                Iteration.Loops
            );
}

此操作完成后:

private void job_OnFinishWorkEventHandler(object sender, EventArgs e)
{
    Job job = sender as Job;
    job.OnStartPlayEventHandler -= job_OnStartPlayEventHandler;
    job.OnFinishPlayEventHandler -= job_OnFinishPlayEventHandler;
    job.OnFinishWorkEventHandler -= job_OnFinishWorkEventHandler;
    job.StartTimerEventHandler -= job_StartTimerEventHandler;
    job.StopTimerEventHandler -= job_StopTimerEventHandler;
    Iteration.LoopFinished++;

    if (Iteration.LoopFinished < Iteration.Loops) // In case i want another loop
        StartJob();
    else
    {
        UnlockButtonsAfterPlay();
        UnlockContextMenuAfterPlay();
    }
}

正如我提到的,所有都卡在第二次迭代中

【问题讨论】:

  • 您很可能需要将您的//Do work 包含在您的问题中,就目前而言,似乎没有任何会影响 gui 的内容

标签: c# .net winforms task-parallel-library task


【解决方案1】:

Task.Factory.StartNew is dangerous。它使用TaskScheduler.Current 而不是TaskScheduler.Default

在您的情况下,OnFinishWorkEventHandlerContinueWith 触发,TaskScheduler.FromCurrentSynchronizationContext() 在 UI 线程中运行。所以那时TaskScheduler.Current 是UIScheduler 而不是TaskScheduler.Default(线程池调度程序)。 这就是为什么您的第二个任务被安排在 UI 线程中,这会导致 UI 冻结。

要解决此问题,请使用始终指向 TaskScheduler.DefaultTask.RunTask.Run 是 .net 4.5 中的新功能,如果您在 .net 4.0 中,您可以使用默认参数创建您的 TaskFactory,您可以使用它。

private static readonly TaskFactory factory = new TaskFactory(CancellationToken.None,
        TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);

然后使用

factory.StartNew(...);

如果您只是在不需要自己创建工厂实例时才使用它,那么只需明确指定 TaskScheduler 就可以了。

Task.Factory.StartNew(() =>{
   //Your code here
}, _tokenSource.Token,
   TaskCreationOptions.None,
   TaskScheduler.Default)//Note TaskScheduler.Default here
.ContinueWith(
        t =>
        {
            //finish...
             if (OnFinishWorkEventHandler != null)
                 OnFinishWorkEventHandler(this, EventArgs.Empty);
        }
    , TaskScheduler.FromCurrentSynchronizationContext());

【讨论】:

  • Task.Run 而不是什么?我需要改变一些东西吗?
  • Task.Run 而不是 Task.Factory.StartNew
  • 我想您使用的是 .net 4.0,请按照我对 .net 4.0 的回答中的解决方法进行操作
  • 您能解释一下如何使用此修复程序吗? (我是新开发者...)
  • 非常感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2023-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多