在Task.Factory.StartNew中暂停任务

时间:2015-01-27 21:23:02

标签: c# multithreading asynchronous task-parallel-library task

在我的Asp.Net MVC 5项目中,我有一个约3分钟的任务,我将其传递给Task.Factory.StartNew()。

如果在任务中运行的代码的其中一个步骤中存在验证问题,我想暂停任务中的任务。我不想将其延迟异步,因为剩下的任务将继续运行,这是不可能发生的。

我可以使用thread.sleep()而不会产生任何影响因为我在任务中吗?我读到我可能必须使用TaskScheduler.Default让Task.Factory为每个任务创建一个新线程。

我正在使用类似于CancellationToken的PauseToken,因此我将能够根据用户输入恢复任务或取消此任务。

多线程真的让我害怕,我不想忽视某些事情。

以下是Thread.Sleep实现的示例:

public void WaitIfPaused(PauseToken pauseToken, CancellationToken cancellationToken, IProgressBar progressBar)
    {
        //TODO: If paused for an hour notify user via noty and abort the task to keep it from completing by cancellation via cancellationToken.
        //wait for 1 hour
        for (int i = 0; i < 3600; i++)
        {
            ThrowExceptionIfCancelled(cancellationToken, progressBar);
            if (pauseToken.IsPaused)
            {
                Thread.Sleep(1000);
            }
            else
            {
                break;
            }

        }
    }

PauseToken:http://blogs.msdn.com/b/pfxteam/archive/2013/01/13/cooperatively-pausing-async-methods.aspx


请求:在共享代码库中实现任务结构。

public void StartTask(params object[] data)
    {
        //throw an exception if no ITask was found
        if (_taskToRun == null)
            throw new Exception("Task cannot be null");

        //set up task cancellation
        CancellationTokenSource = new CancellationTokenSource();
        var cancellationToken = CancellationTokenSource.Token;

        //set up task pausing
        PauseTokenSource = new PauseTokenSource();
        var pauseToken = PauseTokenSource.Token;

        //start a new task using the Task that was set
        _task = Task.Factory.StartNew(() => _taskToRun.Execute(cancellationToken, pauseToken, data), cancellationToken);
}

我的执行方法由_taskToRun.Execute:

调用
Public override void Execute(CancellationToken cancellationToken, PauseToken pauseToken, params object[] data)
    {
        var managerList = (List<IFileManager>) data[0];
        var instr = (List<InstructionSet>) data[1];

        ProcessInstructions(managerList, instr, cancellationToken, pauseToken);
    }

由于评论而更新:

代码示例:3条指令

For(var instruction in instructions)
{
    instruction.Execute();
}

在我的执行方法中,我遇到暂停的场景,并在执行中调用WaitWhilePausedAsync。它将继续执行其他两条指令,但只暂停当前指令的执行方法。

编辑:等待instruction.Execute()它会等到instruction.Execute()完成或取消暂停。


最终编辑: 我能够通过等待Execute方法解决问题,并像Servy和I3arnon建议的那样使其异步。

最终代码示例:

foreach(var instruction in instructions)
{
    try 
    {
        await instruction.Execute(pauseToken);
    }
    catch(InvalidOperationException)
    {
        pauseTokenSource.IsPaused = true;
        //ask if user wants to cancel or resume.
    }
}
//Simplified
public async Task<bool> Execute(PauseToken pauseToken)
{
    await pauseToken.WaitWhilePausedAsync();
    //do work
}

1 个答案:

答案 0 :(得分:0)

您可以安全地使用Thread.Sleep。唯一的缺点是线程会被同步浪费阻塞。

您应该使用await Task.Delay(1000)代替。该行之后的代码在等待完成之前不会执行,但在此期间你不会浪费一个线程:

public async Task WaitIfPausedAsync(PauseToken pauseToken, CancellationToken cancellationToken, IProgressBar progressBar)
{
    for (int i = 0; i < 3600; i++)
    {
        ThrowExceptionIfCancelled(cancellationToken, progressBar);
        if (pauseToken.IsPaused)
        {
            await Task.Delay(1000)
        }
        else
        {
            break;
        }
    }
}

编辑:我不知道PauseToken.WaitWhilePausedAsync。您应该明确地使用它,而不是通过PauseToken.IsPaused

轮询自己复制它
相关问题