Przenosimy aplikację modelującą, która wykorzystuje skrypty IronPython do niestandardowych działań w procesie modelowania. Istniejąca aplikacja wykonuje każdy skrypt Pythona w osobnym wątku i wykorzystuje do tego model współpracy. Teraz chcemy przenieść go na TPL, ale najpierw chcemy zmierzyć przełączanie kontekstów: . Zasadniczo, co mamy teraz:Wielozadaniowość kooperacyjna za pomocą TPL
Task
s kolejka- każdy
Task
z tej kolejki wykonuje skrypt jeden IronPython - Wewnątrz skryptu IronPython wzywamy do C# metody klasy, który jest punktem synchronizacji i powinien przenosić
Task
(IronPython wykonanie) na stanie oczekiwania
co chcemy zrobić:
- Chcemy mieć nieskończoną pętlę, która będzie iterację
Task
s kolejce - gdy mamy jeden
Task
staramy się go - W PythonScript chcemy zadzwonić C Metoda # i przenieść ten skrypt do czekania stan wykonania. ale nie usuwaj go z kolejki.
- W następnej iteracji, gdy otrzymamy kolejny
Task
sprawdzamy, czy jest w stanie oczekiwania. jeśli tak, obudzimy to i spróbujemy wykonać. - W każdej chwili powinniśmy mieć tylko jedną aktywną
Task
- I wreszcie chcemy zmierzyć ile
Task
możemy wykonać za drugim
ja naprawdę nie wiem, czy to coś o wielozadaniowości? Myślimy o niestandardowym TaskScheduler
, czy to dobre podejście? A może ktoś zna lepsze rozwiązanie?
Dzięki.
Aktualizacja:
Ok, więc na przykład, mam taki kod:
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();
}
}
klienta Task Scheduler, to jeden _thread
za wykonanie zadań i _currentTask
dziedzinie na prowadzenie zadania, również ma SleepCurrentTask
w tej metodzie chcę zawiesić bieżące wykonywanie zadań, ale nie wiem jak.
kod klienta jest prosty:
CancellationTokenSource tokenSource = new CancellationTokenSource();
Application app = Application.Create();
Task task = Task.Factory.StartNew(() =>
{
app.Scheduler.SleepCurrentTask();
},
tokenSource.Token, TaskCreationOptions.None, app.Scheduler);
}
Może ktoś ma lepsze pomysły?