从任务调用Thread.Sleep

时间:2013-12-16 12:13:34

标签: .net c#-4.0 task-parallel-library delay thread-sleep

在任务中使用Thread.Sleep()是否正确。或者只是一个与任务一起使用的计时器(.Net 4.5和后者中的Task.Delay())?或者可能存在其他方法。

3 个答案:

答案 0 :(得分:5)

可以在任务中使用Thread.Sleep。 但在大多数情况下,我更喜欢使用await Task.Delay来阻止线程。

如果您正在使用Task.Run(使用ThreadPool线程),那么您应该尽量不阻止该线程。因为它是一个共享线程,所以可能还有其他代码在等待运行。

当我使用线程时,我仍然会使用Thread.Sleep(0)来产生处理器并放弃你的时间片。

答案 1 :(得分:2)

似乎真正的问题是如何在.NET 4.0中实现与.NET 4.5的Task.Delay相同的效果。

首先,如果您使用Visual Studio 2012+,则可以将Microsoft.Bcl.Async nuget包添加到项目中以启用async/await和其他新功能,如Task.Delay。这是最方便的方法。

如果您使用的是Visual Studio 2010,则可以通过创建在计时器到期时完成的TaskCompletionSource来获得相同的结果。这已由ParallelExtensionsExtras库作为一组扩展方法提供。

基本功能是StartNewDelayed,并且有许多方便的重载:

    /// <summary>Creates a Task that will complete after the specified delay.</summary>
    /// <param name="factory">The TaskFactory.</param>
    /// <param name="millisecondsDelay">The delay after which the Task should transition to RanToCompletion.</param>
    /// <param name="cancellationToken">The cancellation token that can be used to cancel the timed task.</param>
    /// <returns>A Task that will be completed after the specified duration and that's cancelable with the specified token.</returns>
    public static Task StartNewDelayed(this TaskFactory factory, int millisecondsDelay, CancellationToken cancellationToken)
    {
        // Validate arguments
        if (factory == null) throw new ArgumentNullException("factory");
        if (millisecondsDelay < 0) throw new ArgumentOutOfRangeException("millisecondsDelay");

        // Check for a pre-canceled token
        if (cancellationToken.IsCancellationRequested)
            return factory.FromCancellation(cancellationToken);

        // Create the timed task
        var tcs = new TaskCompletionSource<object>(factory.CreationOptions);
        var ctr = default(CancellationTokenRegistration);

        // Create the timer but don't start it yet.  If we start it now,
        // it might fire before ctr has been set to the right registration.
        var timer = new Timer(self =>
        {
            // Clean up both the cancellation token and the timer, and try to transition to completed
            try
            {
                ctr.Dispose();
            }
            catch (NullReferenceException)
            {
                // Eat this. Mono throws a NullReferenceException when constructed with
                // default(CancellationTokenRegistration);
            }

            ((Timer)self).Dispose();
            tcs.TrySetResult(null);
        });

        // Register with the cancellation token.
        if (cancellationToken.CanBeCanceled)
        {
            // When cancellation occurs, cancel the timer and try to transition to canceled.
            // There could be a race, but it's benign.
            ctr = cancellationToken.Register(() =>
            {
                timer.Dispose();
                tcs.TrySetCanceled();
            });
        }

        // Start the timer and hand back the task...
        try { timer.Change(millisecondsDelay, Timeout.Infinite); }
        catch(ObjectDisposedException) {} // in case there's a race with cancellation; this is benign

        return tcs.Task;
    }

大多数代码处理正确处理计时器和处理取消。

答案 2 :(得分:0)

在.NET 4.5中,您应该使用Task.Delay。在.NET 4.0中,因为在Task中没有Task.DelayThread.Sleep是一种不好的做法...创建一个自定义任务,并使用一个计时器将ti标记为已完成。