Иногда требуется организовать ожидание до тех пор, пока не завершится любая из группы задач. Для этой цели служит метод WaitAny()
. Ниже приведена простейшая форма его объявления.
public static int WaitAny(params Task[] tasks)
Задачи, завершения которых требуется ожидать, передаются с помощью параметра в виде массива tasks объектов типа Task
или отдельного списка аргументов типа Task
. Этот метод возвращает индекс задачи, которая завершается первой. При этом могут быть сгенерированы различные исключения.
Попробуйте применить метод WaitAny()
на практике, подставив в предыдущей программе следующий вызов.
Task.WaitAny(tsk, tsk2);
Теперь, выполнение метода Main()
возобновится, а программа завершится, как только завершится одна из двух задач.
Помимо рассматривавшихся здесь форм методов Wait(), WaitAll()
и WaitAny()
, имеются и другие их варианты, в которых можно указывать период простоя или отслеживать признак отмены. (Подробнее об отмене задач речь пойдет далее в этой главе.)
Вызов метода Dispose()
В классе Task
реализуется интерфейс IDisposable
, в котором определяется метод Dispose()
. Ниже приведена форма его объявления.
public void Dispose()
Метод Dispose()
реализуется в классе Task
, освобождая ресурсы, используемые этим классом. Как правило, ресурсы, связанные с классом Task
, освобождаются автоматически во время "сборки мусора" (или по завершении программы). Но если эти ресурсы требуется освободить еще раньше, то для этой цели служит метод Dispose()
. Это особенно важно в тех программах, где создается большое число задач, оставляемых на произвол судьбы.
Следует, однако, иметь в виду, что метод Dispose()
можно вызывать для отдельной задачи только после ее завершения. Следовательно, для выяснения факта завершения отдельной задачи, прежде чем вызывать метод Dispose()
, потребуется некоторый механизм, например, вызов метода Wait()
. Именно поэтому так важно было рассмотреть метод Wait()
, перед тем как обсуждать метод Dispose()
. Ели же попытаться вызвать Dispose()
для все еще активной задачи, то будет сгенерировано исключение InvalidOperationException
.
Во всех примерах, приведенных в этой главе, создаются довольно короткие задачи, которые сразу же завершаются, и поэтому применение метода Dispose()
в этих примерах не дает никаких преимуществ. (Именно по этой причине вызывать метод Dispose()
в приведенных выше программах не было никакой необходимости. Ведь все они завершались, как только завершалась задача, что в конечном итоге приводило к освобождению от остальных задач.) Но в целях демонстрации возможностей данного метода и во избежание каких-либо недоразумений метод Dispose()
будет вызываться явным образом при непосредственном обращении с экземплярами объектов типа Task
во всех последующих примерах программ. Если вы обнаружите отсутствие вызовов метода Dispose()
в исходном коде, полученном из других источников, то не удивляйтесь этому. Опять же, если программа завершается, как только завершится задача, то вызывать метод Dispose()
нет никакого смысла — разве что в целях демонстрации его применения.
Применение класса TaskFactory для запуска задачи
Приведенные выше примеры программы были составлены не так эффективно, как следовало бы, поскольку задачу можно создать и сразу же начать ее исполнение, вызвав метод StartNew()
, определенный в классе TaskFactory
. В классе TaskFactory
предоставляются различные методы, упрощающие создание задач и управление ими. По умолчанию объект класса TaskFactory
может быть получен из свойства Factory
, доступного только для чтения в классе Task
. Используя это свойство, можно вызвать любые методы класса TaskFactory
. Метод StartNew()
существует во множестве форм. Ниже приведена самая простая форма его объявления:
public Task StartNew(Action action)
где action — точка входа в исполняемую задачу. Сначала в методе StartNew()
автоматически создается экземпляр объекта типа Task
для действия, определяемого параметром action , а затем планируется запуск задачи на исполнение. Следовательно, необходимость в вызове метода Start()
теперь отпадает.
Например, следующий вызов метода StartNew()
в рассматривавшихся ранее программах приведет к созданию и запуску задачи tsk
одним действием.
Task tsk = Task.Factory.StartNew(MyTask);
Читать дальше