Думаю, в моем случае мне придется использовать Factory.StartNew(), так как я хочу подключить свой собственный TaskScheduler.< /p>
Подводя итог, кажется, что:
Код: Выделить всё
Task.Run(action)
Код: Выделить всё
Task.Factory.StartNew(action,
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.Default);
Вот простой код:
Код: Выделить всё
/// Represents a queue of tasks to be started and executed serially.
public class SerialTaskQueue
{
/// The ordered queue of tasks to be executed. Also serves as a lock protecting all shared state.
private Queue _tasks = new Queue();
/// The task currently executing, or null if there is none.
private Task _taskInFlight;
/// Enqueues the task to be processed serially and in order.
///
The function that generates a non-started task.
public void Enqueue(Func taskGenerator) { EnqueueInternal(taskGenerator); }
/// Enqueues the task to be processed serially and in order.
/// The task or functino that generates a task.
/// The task must not be started and must only be started by this instance.
private void EnqueueInternal(object taskOrFunction)
{
// Validate the task
if (taskOrFunction == null) throw new ArgumentNullException("task");
lock (_tasks)
{
// If there is currently no task in flight, we'll start this one
if (_taskInFlight == null) StartTask_CallUnderLock(taskOrFunction);
// Otherwise, just queue the task to be started later
else _tasks.Enqueue(taskOrFunction);
}
}
/// Starts the provided task (or function that returns a task).
/// The next task or function that returns a task.
private void StartTask_CallUnderLock(object nextItem)
{
Task next = nextItem as Task;
if (next == null) next = ((Func)nextItem)();
if (next.Status == TaskStatus.Created) next.Start();
_taskInFlight = next;
next.ContinueWith(OnTaskCompletion);
}
/// Called when a Task completes to potentially start the next in the queue.
/// The task that completed.
private void OnTaskCompletion(Task ignored)
{
lock (_tasks)
{
// The task completed, so nothing is currently in flight.
// If there are any tasks in the queue, start the next one.
_taskInFlight = null;
if (_tasks.Count > 0) StartTask_CallUnderLock(_tasks.Dequeue());
}
}
}
Код: Выделить всё
public static async Task SimulateTaskSequence(int taskId)
{
Console.WriteLine("Task{0} - Start working 1sec (ManagedThreadId={1} IsThreadPoolThread={2})", taskId, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
Thread.Sleep(200);
Console.WriteLine("Task{0} - Zzz 1st 1sec (ManagedThreadId={1} IsThreadPoolThread={2})", taskId, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
await Task.Delay(200);
Console.WriteLine("Task{0} - Done (ManagedThreadId={1} IsThreadPoolThread={2})", taskId, Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
}
Код: Выделить всё
static void Main(string[] args)
{
Console.WriteLine($"Starting test program (ManagedThreadId={Thread.CurrentThread.ManagedThreadId} IsThreadPoolThread={Thread.CurrentThread.IsThreadPoolThread})");
SerialTaskQueue co_pQueue = new SerialTaskQueue();
for (int i = 0; i < 2; i++)
{
var local = i;
co_pQueue.Enqueue(() => Task.Run(() => { return SimulateTaskSequence(local); }));
}
}
Запуск тестовой программы (ManagedThreadId=1 IsThreadPoolThread=False)
Task0 – начало работы 1 с (ManagedThreadId=5 IsThreadPoolThread=True)
Task0 – Zzz 1-я 1 секунда (ManagedThreadId=5 IsThreadPoolThread=True)
Task0 – Готово (ManagedThreadId=5 IsThreadPoolThread=True)
Task1 – Начало работы 1 секунда (ManagedThreadId=5 IsThreadPoolThread) =True)
Task1 — Zzz 1st 1sec (ManagedThreadId=5 IsThreadPoolThread=True)
Task1 — Done (ManagedThreadId=8 IsThreadPoolThread=True)
Тест 2: просто использование Factory.StartNew с его полной эквивалентностью:
Код: Выделить всё
static void Main(string[] args)
{
Console.WriteLine($"Starting test program (ManagedThreadId={Thread.CurrentThread.ManagedThreadId} IsThreadPoolThread={Thread.CurrentThread.IsThreadPoolThread})");
SerialTaskQueue co_pQueue = new SerialTaskQueue();
for (int i = 0; i < 2; i++)
{
var local = i;
co_pQueue.Enqueue(() => Task.Factory.StartNew(() => { return SimulateTaskSequence(local); }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default));
}
}
Запуск тестовой программы ( ManagedThreadId=1 IsThreadPoolThread=False)
Task0 – начало работы 1 с (ManagedThreadId=5 IsThreadPoolThread=True)
Task0 – Zzz 1 секунда (ManagedThreadId=5 IsThreadPoolThread=True)
Задача 1 — начало работы 1 секунда (ManagedThreadId=5 IsThreadPoolThread=True) ЧТО?
Задача 1 — Zzz 1-я 1 секунда (ManagedThreadId=5 IsThreadPoolThread=True)
Задача 0 — выполнено (ManagedThreadId=9 IsThreadPoolThread=True)
Задача 1 — выполнено (ManagedThreadId=5 IsThreadPoolThread=True)
Я не понимаю разницы. Почему поведение другое? Я думал это эквивалентно?! (помните, что следующий шаг — подключение моего собственного планировщика)
Подробнее здесь: https://stackoverflow.com/questions/474 ... d-task-run