顶级任务导致错误“当前的SynchronizationContext不能用作TaskScheduler." [英] Top Level Task Causes Error "The current SynchronizationContext may not be used as a TaskScheduler."

查看:878
本文介绍了顶级任务导致错误“当前的SynchronizationContext不能用作TaskScheduler."的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尽管我已经看过stackoverflow和文档,但我还没有找到答案.

I do not see the answer yet, although I have looked on stackoverflow and documentation.

如果我调用从计时器处理程序或另一个任务中创建任务的代码,则会在下面的ContinueWidth中出现此错误.例如,如果将其包装在另一个任务中,该任务将按以下间隔(例如,每1秒)创建一个任务.我执行高级任务的唯一原因是每个间隔都创建这些较低的任务.

This error is coming up over the ContinueWidth below if I call the code that creates the tasks from a timer handler or within another task. For example, if it is wrapped in another task that creates tasks every interval (e.g. every 1 second) as follows. The only reason why I have the high level task is to create these lower tasks every interval.

//更高级别的任务创建

//Higher level task creation

...

Task task = Task.Factory.StartNew(new Action(UpdateAllDuringInterval));

...

    private void UpdateAllDuringInterval()
    {
        Stopwatch stopWatch = new Stopwatch();

        do
        {
            // Start the stopwatch
            stopWatch.Start();

            // Create tasks
            List<Task> tasks = CreateTasksAndStart();

            // Wait for the tasks to complete if testing, since want to check results
            if (this._testMode)
            {
                Task[] taskArray = tasks.ToArray();
                Task.WaitAll(taskArray);
            }

            if (!_testMode)
            {
                // Get remaining time to complete interval and sleep for that time
                int remainingTimeInMilliseconds = this._pollingIntervalInMilliseconds -
                                                  (int) stopWatch.Elapsed.TotalMilliseconds;
                    // truncating milliseconds
                if (remainingTimeInMilliseconds > 0)
                    Thread.Sleep(remainingTimeInMilliseconds);
                        // will give time to CPU. Note that using Sleep used to be frowned upon but no longer due to advantages in multitasksing/CPU utilization
            }
        } while (!_testMode); // continue updating stocks once per interval if not testing
    }

    private List<Task> CreateTasksAndStart()
    {
        var tasks = new List<Task>();

        lock (syncLock)
        {
            for (int i = 0; i < _stocksToUpdate.Count; i++)
            {
                var item = _stocksToUpdate[i];
                var initialTask = Task.Factory.StartNew(() =>
                {
                    GetUpdatedStockInformation(item);
                });
                var continuationTask = initialTask.ContinueWith((antecendent) =>
                {
                    UpdateUIWithUpdatedStockInformation();
                }
                , CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion,
                TaskScheduler.FromCurrentSynchronizationContext());

                // For testing, we want to wait on the continuation task to make sure updates are done
                tasks.Add(continuationTask);
            }
        }
        return tasks;
    }

如果需要更多信息,请告诉我.也可以给我这些代码的其他陷阱.谢谢!

If more information is needed, just let me know. Feel free to give me other pitfalls of this code as well. Thanks!

推荐答案

原因很简单,但是该解决方案可能需要您重新设计一些任务交互.您没有设置SynchronizationContext(即SynchronizationContext.Current为空),因此无法从中创建TaskScheduler.一种选择是在您正在UI线程上运行的位置调用TaskScheduler.FromCurrentSynchronizationContext(),然后向下传递到构造延续的方法.另一个方法是创建任务并传递任务,以便UI线程可以附加延续.

The cause is simple however the solution may require you to redesign some of the interactions of your tasks. You do not have a SynchronizationContext set (i.e. SynchronizationContext.Current is null), and therefore a TaskScheduler cannot be created from the it. One option is to call TaskScheduler.FromCurrentSynchronizationContext() in a place where you are running on the UI thread and then pass in down to the method where the continuations are constructed. Another is create the tasks an pass them up so that the UI thread can attach the continuations.

通常认为具有诸如_testMode之类的标志的代码味道大概只是测试代码集.然后,您得到了一些您尚未真正测试的交互,因为测试代码可以完成一件事,而实际的应用程序可以完成另一件事.

It is generally considered a code smell to have flags like _testMode that, presumably, only test code sets. Then you've got some interaction which you are not really testing because the test code does one thing, but the actual application does another.

这篇关于顶级任务导致错误“当前的SynchronizationContext不能用作TaskScheduler."的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆