将参数传递给Task.Factory.StartNew

时间:2013-11-18 11:49:26

标签: c# asp.net garbage-collection task

给出以下代码:

string injectedString = "Read string out of HttpContext";
Task.Factory.StartNew(() =>
 {
    MyClass myClass = new MyClass();
    myClass.Method(injectedString);
 }

这是将字符串传递给Task / Thread的最佳方法吗?

我对这种方法的担忧是:

  • 垃圾收集器会知道字符串何时消失 上下文并正确清理它?
  • 是否有更好的方法将依赖项注入到主要线程中断开对象链接的任务中?

这是在Asp.Net网络服务中,如果它很重要并且是一个火灾和忘记类型的线程,我不会等待任何类型的响应。

我的字符串实际上是从HttpContext中读出来的,这是我以这种方式注入它的一个原因(Thread无法访问调用线程HtppContext)< / p>

3 个答案:

答案 0 :(得分:10)

您应该使用Task.Factory.StartNew(Action<object> action, object state)重载将状态传递给新任务。

Task.Factory.StartNew((object myState) => {
    var i = (int)myState;

    //Do calculations...
    var x = i + 10; 
}, 10);

答案 1 :(得分:9)

您的lambda将被提升到编译器生成的类中。 injectedString变量将成为该类的字段。

因此,当生成的类超出范围(基本上在lambda的最后)时,它将被垃圾收集,并且GC决定执行收集。

回应你的评论:

没有重复。编译器将其转为:

 string injectedString = "Read string out of HttpContext";
 Task.Factory.StartNew(() =>
 {
    MyClass myClass = new MyClass();
    myClass.Method(injectedString);
 }

进入这个:

CompilerGeneratedClass c1 = new CompilerGeneratedClass();
c1.injectedString = "Read string out of HttpContext";
// call delegate here.

还要记住:字符串是在CLR中实现的。即使代码是重复的,字符串文字也会在池中实现。您基本上只有一个本地WORD大小的引用重复指向字符串(仅限字符串文字..)

答案 2 :(得分:1)

如果您担心injectedString可能会在myClass.Method(injectedString);运行之前“收集垃圾”?

答案是。您无需担心这一点,因为injectedStringlambda关闭时不再是局部变量。它将成为新编译器生成的类中的一个字段。

如果您担心垃圾收集器会在合适的时间收集它吗? 答案是,当该类的实例超出范围且在托管代码中没有引用它时,它会执行。在Task 完成并且超出范围之后,肯定会发生这种情况。