Совместная многозадачность с использованием TPL - PullRequest
7 голосов
/ 13 октября 2010

Мы портируем приложение для моделирования, которое использует скрипты IronPython для пользовательских действий в процессе моделирования. Существующее приложение выполняет каждый скрипт Python в отдельном потоке и использует для этого модель сотрудничества. Теперь мы хотим перенести его на TPL, но сначала мы хотим измерить переключение контекста. , В основном то, что мы имеем сейчас:

  1. Task s очередь
  2. каждый Task из этой очереди выполняет один скрипт IronPython
  3. Внутри скрипта IronPython мы вызываем метод класса C #, который является точкой синхронизации и должен перевести Task (выполнение IronPython) в состояние ожидания

Что мы хотим сделать:

  1. Мы хотим сделать бесконечный цикл, который будет перебирать очередь Task s
  2. когда мы получаем один Task, мы пытаемся выполнить его
  3. В PythonScript мы хотим вызвать метод C # и перевести этот скрипт в состояние ожидания. но не удаляйте его из очереди.
  4. На следующей итерации, когда мы получаем еще Task, мы проверяем, находится ли она в состоянии ожидания. если это так, мы просыпаемся и пытаемся выполнить.
  5. В каждый момент у нас должен быть только один активный Task
  6. И, наконец, мы хотим измерить, сколько Task мы могли бы выполнить в секунду

Я действительно не знаю, это что-то о совместной многозадачности? Мы думаем о кастомах TaskScheduler, это хороший подход? Или кто-то знает лучшее решение?

Спасибо.

Обновлен:

Хорошо, например, у меня есть такой код:

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();
        }
   }

Пользовательский планировщик задач, у него есть одно _thread для выполнения задачи и _currentTask поле для запуска задачи, также в этом методе есть SleepCurrentTask. В этом методе я хочу приостановить текущее выполнение задачи, но я не знаю как.

Код клиента прост:

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


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

Может быть, у кого-то есть идеи получше?

1 Ответ

2 голосов
/ 17 октября 2010

Звучит так, что вам будет хорошо использовать шаблон «производитель / потребитель». В состав нескольких коллекций встроено .NET 4.

Посетите страницу 55 в этом бесплатном PDF-документе Microsoft, Шаблоны параллельного программирования

...