2013-11-18 4 views
11

Учитывая следующий код:Передача параметра в Task.Factory.StartNew

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

Это лучший способ передать строку в Task/Thread?

Мои проблемы с этим методом:

  • ли сборщик мусора знать, когда строка стала из контекста и правильно очистить его?
  • Есть ли лучший способ встраивания зависимостей в задачу, нарушающую связь с объектом в основном потоке?

Это в веб-сервисе Asp.Net, если это имеет значение и является потоком огня и забытого типа, я не жду никакого ответа.

Моя строка на самом деле происходит, чтобы считывать из HttpContext, что одна из причин, почему я впрыскиванием таким образом (Thread не имеет доступа к призывающих потоков HtppContext)

ответ

9

Ваш лямбда будет выведен в класс, сгенерированный компилятором. Переменная injectedString станет полем этого класса.

Таким образом, это будет сбор мусора, когда сгенерированный класс выходит за рамки (который находится в основном в самом конце вашей лямбда), и 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 размерный дубликат, который указывает на строку (только строковые литералы ..)

+0

Вот что мне нужно было знать. Благодарю. Итак, просто чтобы уточнить, каждая введенная ссылка будет дублироваться в новом классе, сгенерированном компилятором? Значит, в памяти у меня было бы две несвязанные строки? – Liam

+0

Это действительно зависит от того, что вы делаете со строками. С тем, что вы здесь указали, объявление всей строки оптимизировано и вместо этого заменяется на экземпляр класса, сгенерированного компилятором, и поле этого класса присваивается значению строковой переменной. Я уточню свой ответ, чтобы понять, что я имею в виду. –

9

Вы, вероятно, следует использовать Task.Factory.StartNew(Action<object> action, object state) перегрузка, чтобы передать состояние в вашу новую задачу.

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

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

этот код не компилируется? Кастинг с строкой, затем вызов метода на нем? – Liam

+0

Метод DoSomething в строке - это всего лишь образец .... Позвольте мне изменить что-то, что компилируется ... – tucaz

+0

Не уверен, что он отвечает на мой вопрос, но интересно посмотреть, как работает государство. +1 – Liam

1

Если вы обеспокоены injectedString может быть «сборки мусора» перед myClass.Method(injectedString); работает?

Ответа на этот вопрос не было. Вам не нужно об этом беспокоиться, потому что injectedString больше не является локальной переменной, когда она закрыта в lambda. Он станет полем нового класса, сгенерированного компилятором.

Если вас беспокоит, сборщик мусора соберет его в нужное время? Ответа на этот вопрос yes Это будет делать, если экземпляр этого класса выходит из области видимости и не ссылается на него в управляемом коде. Это произойдет, конечно, после того, как Taskзакроется и выходит из сферы действия.

+0

Это было более наоборот, сможет ли сборщик мусора очистить строку (или это может быть большой объект и т. Д.), Как только поток закончится? – Liam

+0

@Liam обновил мой ответ –

-3
class Program 
    { 
     static readonly ConcurrentQueue<int> mockItems = new ConcurrentQueue<int>(Enumerable.Range(0, 100)); 
     static CancellationToken token; 
     static CancellationTokenSource tokenSource; 
     static void Main(string[] args) 
     { 
      tokenSource = new CancellationTokenSource(); 
      token = tokenSource.Token; 

      for (int i = 0; i < 5; i++) 
      { 
       Task.Factory.StartNew(delegate { StartProcess(); }, tokenSource.Token, TaskCreationOptions.LongRunning); 
      } 
      Console.Read(); 
      tokenSource.Cancel(); 

     } 
     private static void StartProcess() 
     { 
      while (true) 
      { 
       if (token.IsCancellationRequested) 
        break; 

       int result; 
       mockItems.TryDequeue(out result); 

       Console.WriteLine(result); 
       Thread.Sleep(1000); 
      } 

     } 
    } 
Смежные вопросы