如何使用并行扩展在低优先级线程上串行处理排队项目

发布于 2024-10-03 12:53:39 字数 1162 浏览 6 评论 0原文

我想知道使用 .NET 4.0 并行扩展

我有以下类,既执行执行又提供结果:

public class Step 
{
  public string Name { get; set; }
  public TimeSpan Duration { get; set; }
  public bool Completed { get; set; }

  public void Execute() 
  {
     DateTime before = DateTime.Now;
     RemotedService.DoSomeStuff();
     Duration = DateTime.Now - before;
     Completed = true;
  }
}

如何处理这些步骤并在处理后按顺序将它们保存到文件中?我想在 RemotedService.DoSomeStuff() 等待服务器响应时将它们保存到文件中。

写入文件的方式如下:

using (StreamWriter w = File.AppendText("myFile.txt"))
{
  var completedStep = completedSteps.Dequeue();
  w.WriteLine(string.Format("Completed {0} with result: {1} and duration {2}", 
                            completedStep.Name, 
                            completedStep.Completed, 
                            completedStep.Duration));
}

我想到的一个选项是将它们添加到队列中,并让一个计时器来处理它们。但这并没有利用远程调用的停机时间。

我想到的另一个选择是使用每个 Step 使用 System.Threading.Tasks.Task 将每个结果异步写入文件,但这并不能保证它们会按顺序保存,并且还可能引入写入文件的争用。

I want to know what the best way to process the results of a long-running process serially but on a low-priority thread using the .NET 4.0 Parallel Extensions.

I have the following class that both does the execution and provides the results:

public class Step 
{
  public string Name { get; set; }
  public TimeSpan Duration { get; set; }
  public bool Completed { get; set; }

  public void Execute() 
  {
     DateTime before = DateTime.Now;
     RemotedService.DoSomeStuff();
     Duration = DateTime.Now - before;
     Completed = true;
  }
}

How can I process these steps and also save them to a file, in order, after they are processed? I would like to save them to a file while RemotedService.DoSomeStuff() is waiting for a response from the server.

Writing to the file would be like this:

using (StreamWriter w = File.AppendText("myFile.txt"))
{
  var completedStep = completedSteps.Dequeue();
  w.WriteLine(string.Format("Completed {0} with result: {1} and duration {2}", 
                            completedStep.Name, 
                            completedStep.Completed, 
                            completedStep.Duration));
}

One option that comes to mind is to add them to a Queue and have a Timer that processes them. But this doesn't take advantage of the downtime of the remoted calls.

Another option that comes to mind is to asynchronously write each result to the file using a System.Threading.Tasks.Task per Step, but that doesn't guarantee that they will be saved in order and may also introduce contention with writing to the file.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

所谓喜欢 2024-10-10 12:53:39

我建议创建一个 BlockingCollection (请参阅 System.Collections.Concurrent 命名空间)。每个步骤完成后,都会将其添加到该集合中。 BlockingCollection 的默认行为是充当队列,因此您将获得所需的 FIFO 行为。

第二个线程为队列提供服务,删除每个项目并将其写入日志文件。

因此,如果您添加了队列:

static private BlockingCollection<Step> LogQueue = new BlockingCollection<Step>();

您将在项目完成后将其添加到您的 Execute 方法中:

LogQueue.Add(this);

以及您的日志记录线程,您将在静态构造函数中启动

static void LoggingThread()
{
    using (var w = new StreamWriter(...))
    {
        while (!LogQueue.IsCompleted())
        {
            Step item;
            if (LogQueue.TryTake(out item))
            {
                w.WriteLine(....);
            }
        }
    }
}

该日志记录线程 :我已经写过它使用 System.Threading 线程。使用 TPL 可能有一种更简单或更好的方法。我对 TPL 还不是很熟悉,所以我不能说。

I would suggest creating a BlockingCollection<Step> (see System.Collections.Concurrent namespace). As each step is completed, it's added to that collection. The default behavior of BlockingCollection is to function as a queue, so you'll get the FIFO behavior you're looking for.

A second thread services the queue, removing each item and writing it to a log file.

So, if you added the queue:

static private BlockingCollection<Step> LogQueue = new BlockingCollection<Step>();

You would add this to your Execute method, after the item is completed:

LogQueue.Add(this);

And your logging thread, which you would start in the static constructor:

static void LoggingThread()
{
    using (var w = new StreamWriter(...))
    {
        while (!LogQueue.IsCompleted())
        {
            Step item;
            if (LogQueue.TryTake(out item))
            {
                w.WriteLine(....);
            }
        }
    }
}

The logging thread as I've written it uses a System.Threading thread. There might be an easier or better way to do it with TPL. I'm not yet terribly familiar with TPL, so I couldn't say.

神经暖 2024-10-10 12:53:39

一种方法是创建自定义任务计划程序(请参阅 http://msdn.microsoft. com/en-us/library/ee789351.aspx)。您的自定义任务计划程序可以将并发限制为一次一个,并强制执行严格的按顺序执行。

创建任务调度程序还允许您控制线程优先级,或在某些情况下可能需要的 ApartmentState。

One approach is to create a custom Task Scheduler (see http://msdn.microsoft.com/en-us/library/ee789351.aspx). Your custom task scheduler can limit concurrency to one-at-a-time and enforce strict in-order execution.

Creating a task scheduler also allows you to control the thread priority, or the ApartmentState which may be desirable in some situations.

宫墨修音 2024-10-10 12:53:39

您实际上是在描述 Workflow Foundation 的用例 - 它为您完成所有这些工作:)

You're literally describing the use case for Workflow Foundation - it does all of this stuff for you :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文