为什么长时间运行的任务仍会阻止UI?

Jos*_*sso 3 c# wpf task-parallel-library

我正在尝试解决我的UI被阻止的问题,我不明白为什么.

public Task AddStuff(string myID, List<string> otherIDs)
{
    Action doIt = () =>
    {
        this.theService.AddStuff(myID, otherIDs);
    };

    return Task.Factory.StartNew(doIt, TaskCreationOptions.LongRunning);
}
Run Code Online (Sandbox Code Playgroud)

如果列表很长,则呼叫可能需要30秒,并且整个应用程序将无响应(在Windows 7中将其清除为白色).

是否有不同的方法来执行此操作,因此它不会阻止UI?


编辑

好的,所以有很多代码围绕着我,我将尝试保持这个相关性.我确实意识到回到原始代码,我删除了一些可能很重要的东西.我应该使用不同的TaskScheduler TaskScheduler.Current吗?

此外,没有Wait语句阻碍任何此代码,并且该服务不与UI交互.

Task.Factory.StartNew(objState =>
    {
        LoadAssets(objState);
    }, state, this.cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current);
Run Code Online (Sandbox Code Playgroud)
private void LoadAssets(object objState)
{
    LoadAssetsState laState = (LoadAssetsState)objState;

    List<string> assetIDs = new List<string>();

    for (int i = 0; i < laState.AddedMediaItems.Count; i++)
    {
        if (laState.CancellationToken.IsCancellationRequested)
            return;

        string assetId = this.SelectFilesStep.AssetService.GetAssetId(laState.AddedMediaItems[i], laState.ActiveOrder.OrderID);

        assetIDs.Add(assetId);

    }

    if (laState.CancellationToken.IsCancellationRequested)
        return;

    this.ApiContext.AddAssetToProduct(laState.ActiveOrder.OrderID, laState.ActiveProduct.LineID, assetIDs, laState.Quantity, laState.CancellationToken).ContinueWith(task =>
    {
        if (laState.CancellationToken.IsCancellationRequested)
            return;


        App.ApiContext.GetOrderDetails(laState.ActiveOrder.OrderID, false, laState.CancellationToken).ContinueWith(orderDetailsTask =>
        {
            if (laState.CancellationToken.IsCancellationRequested)
                return;

            this.activeOrder = orderDetailsTask.Result;

            this.StandardPrintProductsStep.Synchronize(this.activeOrder);

        });
    });
}
Run Code Online (Sandbox Code Playgroud)
public Task AddAssetToProduct(string orderID, string lineID, List<string> assetIDs, int quantity, CancellationToken? cancellationToken = null)
{
    Action doIt = () =>
    {
        if (cancellationToken.IsCancellationRequested())
            return;

        this.ordersService.AddAssetToProduct(orderID, lineID, assetIDs, quantity);
    };

    if (cancellationToken != null)
        return Task.Factory.StartNew(doIt, cancellationToken.Value, TaskCreationOptions.LongRunning, TaskScheduler.Current);
    else
        return Task.Factory.StartNew(doIt, TaskCreationOptions.LongRunning);
}
Run Code Online (Sandbox Code Playgroud)

编辑

我在服务调用之前和之后放置了断点,它是阻止UI的服务调用,而不是任何其他行.

这听起来似乎没有理由阻止它,所以我想如果它很长并且进行多次调用我只会打破列表.我只是想通过我的Task逻辑来确保我没有遗漏一些东西.

Ree*_*sey 6

是否有不同的方法来执行此操作,因此它不会阻止UI?

此调用本身不应阻止UI.但是,如果theService.AddStuff与UI的SynchronizationContext进行某些同步,则可能导致该调用有效地阻止UI.

否则,问题可能发生在此功能之外.例如,如果调用Wait()此方法返回的任务,则在UI线程中,UI线程将被阻止,直到完成为止.


您可能想要使用TaskScheduler.Default,而不是TaskScheduler.Current.如果在基于UI线程在TaskScheduler上调度的Task中调用它,它将在UI线程上安排自己.