c# - 异步任务暂停循环恢复

标签 c# task-parallel-library async-await

<分区>

我有一个示例代码,取自 MSDN,我想在其中实现 while 循环中的暂停/恢复功能。任何人都可以提出一个解决方案/parern 来解决这个问题吗?

 private async void startButton_Click(object sender, RoutedEventArgs e)
    {
        resultsTextBox.Clear();

        // Instantiate the CancellationTokenSource.
        cts = new CancellationTokenSource();

        try
        {
            await AccessTheWebAsync(cts.Token);
            resultsTextBox.Text += "\r\nDownloads complete.";
        }
        catch (OperationCanceledException)
        {
            resultsTextBox.Text += "\r\nDownloads canceled.\r\n";
        }
        catch (Exception)
        {
            resultsTextBox.Text += "\r\nDownloads failed.\r\n";
        }

        cts = null;
    }


    private void cancelButton_Click(object sender, RoutedEventArgs e)
    {
        if (cts != null)
        {
            cts.Cancel();
        }
    }


    async Task AccessTheWebAsync(CancellationToken ct)
    {
        HttpClient client = new HttpClient();

        // Make a list of web addresses.
        List<string> urlList = SetUpURLList();

        // ***Create a query that, when executed, returns a collection of tasks.
        IEnumerable<Task<int>> downloadTasksQuery =
            from url in urlList select ProcessURL(url, client, ct);

        // ***Use ToList to execute the query and start the tasks. 
        List<Task<int>> downloadTasks = downloadTasksQuery.ToList();

        // ***Add a loop to process the tasks one at a time until none remain. 
        while (downloadTasks.Count > 0)
        {
                // Identify the first task that completes.
                Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);

                // ***Remove the selected task from the list so that you don't 
                // process it more than once.
                downloadTasks.Remove(firstFinishedTask);

                // Await the completed task. 
                int length = await firstFinishedTask;
                resultsTextBox.Text += String.Format("\r\nLength of the download:  {0}", length);
        }
    }

最佳答案

有一个MSDN article使用 PauseToken(类似于 CancellationToken)解决此问题。

下面是那篇文章中演示此概念的示例代码:

namespace PauseTokenTestApp
{
    public class PauseTokenSource
    {
        private volatile TaskCompletionSource<bool> m_paused;
        internal static readonly Task s_completedTask = Task.FromResult(true);

        public bool IsPaused
        {
            get { return m_paused != null; }
            set
            {
                if (value)
                {
                    Interlocked.CompareExchange(
                        ref m_paused, new TaskCompletionSource<bool>(), null);
                }
                else
                {
                    while (true)
                    {
                        var tcs = m_paused;
                        if (tcs == null) return;
                        if (Interlocked.CompareExchange(ref m_paused, null, tcs) == tcs)
                        {
                            tcs.SetResult(true);
                            break;
                        }
                    }
                }
            }
        }
        public PauseToken Token { get { return new PauseToken(this); } }

        internal Task WaitWhilePausedAsync()
        {
            var cur = m_paused;
            return cur != null ? cur.Task : s_completedTask;
        }
    }

    public struct PauseToken
    {
        private readonly PauseTokenSource m_source;
        internal PauseToken(PauseTokenSource source) { m_source = source; }

        public bool IsPaused { get { return m_source != null && m_source.IsPaused; } }

        public Task WaitWhilePausedAsync()
        {
            return IsPaused ?
                m_source.WaitWhilePausedAsync() :
                PauseTokenSource.s_completedTask;
        }
    }

    class Program
    {
        static void Main()
        {
            var pts = new PauseTokenSource();
            Task.Run(() =>
            {
                while (true)
                {
                    Console.ReadLine();
                    pts.IsPaused = !pts.IsPaused;
                }
            });
            SomeMethodAsync(pts.Token).Wait();
        }

        public static async Task SomeMethodAsync(PauseToken pause)
        {
            for (int i = 0; i < 100; i++)
            {
                Console.WriteLine(i);
                await Task.Delay(100);
                await pause.WaitWhilePausedAsync();
            }
        }
    }
}

关于c# - 异步任务暂停循环恢复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20185848/

相关文章:

c# - vb.Net c# 运行批处理文件并流式传输其输出

c# - 运行多个后台任务的最佳做法是什么

c# - 在 asp.net 进程中运行多个并行任务的正确方法是什么?

c# - 如何处理来自多个线程的单个结果?

javascript - Node js 中的动态异步等待

c# - 带外键的 Fluent nHibernate "not-null property references a null or transient value"

c# - 属性 'Id'是对象关键信息的一部分,不可修改

dart - 这个带有异步的 getter 变量如何在 DART 中工作

c# - 重启一个进程

javascript - 我的代码是使用异步等待的最佳方式吗?