一般地运行任务

时间:2011-10-04 14:36:53

标签: c# .net .net-4.0 task task-parallel-library

在我的项目中,我大量使用TPL,我决定设计一种生成任务的通用方法,而不是明确地调用new Task(Action);new Task(Action<object>, object);Task.Factory.StartNew(Action)等。 我将有一个像

这样的功能
void SpawnTask<A,B>( Action<A,B> action, A a, B b) { ... }
void SpawnTask<A,B,C>( Action<A,B,C> action, A a, B b, C c) { ... }

用于创建和启动任务。

此外,我需要在每个任务完成后运行强制方法。因此,我必须包含我想要在另一种方法(如

)中运行的实际方法
void RuncTask(Action action)
{
  action();
  MandatoryMethod();
}

到目前为止,我提出了两种不同的方法 首先,使用匿名代表:

void SpawnTask<A,B>(Action<A,B> action, A a, B b)
{
  A dummyA = a; // To localize the parameters.
  B dummyB = b;
  var methodDelegate = delegate { action(dummyA,dummyB); };
  var taskDelegate = delegate { RunTask(methodDelegate); };
  Task.Factory.StartNew( taskDelegate );
}

void RuncTask(Action action)
{
  action();
  MandatoryMethod();
}

其次,使用元组:

void SpawnTask<A,B>(Action<A,B> action, A a, B b)
{
  Tuple<Action<A,B>, A, B> tpl = Tuple.Create(action, a, b);
  Action<object> act = RunTask<A,B>;
  Task.Factory.StartNew( act, tpl );
}

void RuncTask<A,B>(object obj)
{
  var tpl = (Tuple<Action<A, B>, A, B>)param;
  tpl.Item1(tpl.Item2,tpl.Item3);
  MandatoryMethod();
}

我喜欢第一个,因为它更简单。第二个具有强制转换,需要为不同数量的参数实现其他通用RunTask方法。但我不知道创建太多的匿名代表是否会导致副作用。

您更喜欢哪一个?为什么?或者你有什么其他解决方案?

2 个答案:

答案 0 :(得分:3)

好吧,你总是可以在Action<TA,TB>上创建一个扩展方法......你应该使用continuation而不是包装方法调用来实现在任务完成时总是执行另一个动作的行为:

public static class TaskExtensions
{
    public static void RunTask<TA,TB>( Action<TA,TB> action, TA a, TB b )
    {
        Task newTask = new Task( () => action(a,b) );
        newTask.ContinueWith( MandatoryMethod );
        newTask.Start();
    }

    // if you need to support other signature (more parameters) you would need to
    // create additional overloads of RunTask with more generic parameters...
    public static void RunTask( Action action );
    public static void RunTask<TA>( Action<TA> action, TA a );
    // etc ...

    private static void MandatoryMethod( Task t ) { /* your continuation logic */ }
}

现在您可以按如下方式使用此代码:

public void SomeMethod( int x, int y ) { ... }

// later...
Action<int,int> myAction = SomeMethod;
myAction.RunTask( 1, 2 );

请注意,在上面的实现中,将继续异步执行continuation方法(MandatoryMethod)。如果您希望同步执行(如您的示例中所示),则可以使用ContinueWith的重载,该重载需要TaskContinuationOptions并传入TaskContinuationOptions.ExecuteSynchronously

答案 1 :(得分:1)

坦率地说,我很清楚你想要用它做什么。直接使用Task构造函数或Task.Factory您希望实现什么优势?

对于需要在任务完成后执行的“强制方法”,请查看延续(例如Task.ContinueWith)。