【问题标题】:Task Parallel Library sequential access in .net.net 中的任务并行库顺序访问
【发布时间】:2013-09-22 00:11:30
【问题描述】:

我正在编写一个显示文件下载状态的组件。有一个应用程序可以访问我的组件的方法并传递参数,该参数进一步包含我需要在屏幕上显示的信息。

因此该服务非常频繁地访问我的方法,因为它需要为我提供大量文件的信息(当前正在下载队列中)

 private void ProcessMessage(MessageOptions options)
  {
        Task t= Task.Factory.StartNew(()=>
        {
           //update data row using options object
        });    

        Task t1 = t.ContinueWith((continution) =>
               {
                 //here goes the code to update the MainUI   
               }
            ,TaskScheduler.FromCurrentSynchronizationContext());
        }

所以这可以满足我的一切需求,到目前为止,我还没有遇到这种方法的任何实际问题。 但是这种方法有一个潜在的问题。由于此方法继续被调用,这可能会发生

调用 1 选项。FileName="文件 1" options.DataTransferred="3 mb"

调用 2 选项。FileName="文件 2" options.DataTransferred="6 mb"

调用 3 选项。FileName="文件 1" options.DataTransferred="6 mb"

等等。每次调用此方法时,都会初始化一个新任务,当任务完成时,它会使用信息更新 MainUI。

问题

无法保证先完成哪个任务。有可能Call3先完成并显示文件1下载6mb的信息,然后Call1完成并更新文件1下载3mb的信息,这绝对不能接受。

我想确保任务 1 必须在任务 3 之前完成,因为这两个任务都获得了文件 1 的信息。

谢谢

【问题讨论】:

  • @svick 我在问题中提到它还没有失败。但我看不出有什么理由可以证明我将来不会失败。任务可以按任何顺序完成,因此可能会导致问题。
  • MessageOptions 是只包含一条消息还是多条消息?
  • @Slugart 一次一条消息
  • “有一些 Windows 服务可以访问我的应用程序的方法” - 客户端调用服务器还是相反?如果是客户端,这发生在哪个线程上?
  • @Slugart 抱歉,我已经更新了问题。

标签: c# .net multithreading task-parallel-library


【解决方案1】:

如果您可以修改服务器并将版本号添加到正在发送的消息中,您随后可以丢弃版本小于为该文件接收的最后一个版本的任何消息。

您也可以在更新数据行之前在客户端添加版本号,只要消息以正确的顺序到达ProcessMessage即可。

【讨论】:

  • 这似乎是一个 hack。即使这次我以某种方式修改了服务器,也不能保证下次遇到这个问题时我能做到。
  • 是的,这似乎是可行的。不过我需要测试一下。
【解决方案2】:

如果我正确理解您的问题,您希望您的任务独立运行,但无论任务何时完成,您都希望继续按顺序运行。

我会使用这样的并发队列:

private ConcurrentQueue<Task<MessageOptions>> _tasks = new ConcurrentQueue<Task<MessageOptions>>();

private void ProcessMessage(MessageOptions options)
{
    var t= Task<MessageOptions>.Factory.StartNew(()=>
    {
       //update data row using options object
       return options;
    });    

    _tasks.Enqueue(t);

    Task t1 = t.ContinueWith(_ =>
    {
        // everytime a task finishes, update the UI for all completed tasks from the start of the queue
        Task<MessageOptions> firstInQueue;

        while (_tasks.TryPeek(out firstInQueue) &&
               firstInQueue.IsCompleted)
        {
            // this alwys runs in the same thread we can be sure the item is still in the queue
            _tasks.TryDequeue(out firstInQueue);

            var taskOptions = firstInQueue.Result;
            //here goes the code to update the MainUI
        }
    }
    ,TaskScheduler.FromCurrentSynchronizationContext());
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多