使用TPL的协作多任务处理

7 投票
1 回答
2735 浏览
提问于 2025-04-16 05:24

我们正在移植一个建模应用程序,这个程序使用IronPython脚本来执行建模过程中的自定义操作。现在的应用程序会在不同的线程中执行每个Python脚本,并采用协作模型。我们想把它移植到TPL(任务并行库),但首先想测量一下上下文切换的情况。

目前我们有的内容:

  1. 一个任务队列
  2. 这个队列中的每个任务执行一个IronPython脚本
  3. 在IronPython脚本中,我们调用一个C#类的方法,这个方法是一个同步点,应该把任务(IronPython的执行)转为等待状态

我们想要做的事情:

  1. 我们想创建一个无限循环,遍历任务队列
  2. 当我们获取到一个任务时,尝试执行它
  3. 在Python脚本中,我们想调用C#的方法,把这个脚本转为等待状态,但不从队列中移除它。
  4. 在下一次循环中,当我们获取到另一个任务时,检查它是否处于等待状态。如果是,就把它唤醒并尝试执行。
  5. 在任何时刻,我们应该只有一个活跃的任务
  6. 最后,我们想测量每秒能执行多少个任务

我不太确定这是否与协作多任务有关?我们在考虑自定义的任务调度器,这样做是否合适?或者有没有人知道更好的解决方案?

谢谢。

更新:

好吧,比如说,我有这样的代码:

public class CooperativeScheduler : TaskScheduler, IDisposable
    {
        private BlockingCollection<Task> _tasks;

        private Thread _thread;

        private Task _currentTask;

        public CooperativeScheduler()
        {
            this._tasks = new BlockingCollection<Task>();
            this._thread = new Thread(() =>
                {
                    foreach (Task task in this._tasks.GetConsumingEnumerable())
                    {
                        this._currentTask = task;

                        TryExecuteTask(this._currentTask);
                    }
                }
            );

            this._thread.Name = "Cooperative scheduler thread";

            this._thread.Start();
        }

        public void SleepCurrentTask()
        {
            if (this._currentTask != null)
            {
                // what to do here?
            }
        }

        protected override IEnumerable<Task> GetScheduledTasks()
        {
            return this._tasks.ToArray<Task>();
        }

        protected override void QueueTask(Task task)
        {
            // No long task
            this._tasks.Add(task);
        }

        protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
        {
            throw new NotImplementedException();
        }

        public void Dispose()
        {
            this._tasks.CompleteAdding();
            this._thread.Join();
        }
   }

自定义任务调度器,它有一个线程用于任务执行,还有一个字段用于当前正在运行的任务。此外,它有一个方法叫做,我想在这个方法中暂停当前任务的执行,但我不知道该怎么做。

客户端代码很简单:

    CancellationTokenSource tokenSource = new CancellationTokenSource();
    Application app = Application.Create();


    Task task = Task.Factory.StartNew(() =>
    {
        app.Scheduler.SleepCurrentTask();
    },
     tokenSource.Token, TaskCreationOptions.None, app.Scheduler);
}

也许有人有更好的想法?

1 个回答

2

听起来你可以考虑使用生产者/消费者模式,这个模式在.NET 4中已经内置在一些集合里了。

你可以查看微软提供的这本免费PDF的第55页,里面有相关内容,链接在这里:并行编程模式

撰写回答