Можно ли перенести выполнение делегата из одного потока в другой? - PullRequest
9 голосов
/ 09 августа 2011

Есть ли способ, которым я могу абстрагироваться от того, в каком потоке может выполняться конкретный делегат, чтобы я мог выполнить его в вызывающем потоке изначально, но перенесу выполнение в фоновый поток, если в итоге это займет больше времени, чем определенное количество время

Предположим, что делегат записан как асинхронный. Я не пытаюсь брать синхронные блоки и перемещать их в фоновые потоки для увеличения параллелизма, а скорее хочу повысить производительность асинхронного выполнения, избегая накладных расходов потоков на простые операции.

В основном мне интересно, есть ли способ приостановить выполнение делегата или лямбды, перенести его в другой поток и возобновить, если бы я мог установить четкие границы стека и т. Д.

Я сомневаюсь, что это возможно, мне просто любопытно.

Ответы [ 3 ]

3 голосов
/ 09 августа 2011

Это возможно, но было бы неловко и трудно получить права.Лучший способ добиться этого - использовать сопрограммы .Единственный механизм в .NET, который в настоящее время соответствует парадигме сопрограммы, - это итераторы C # через ключевое слово yield return.Вы могли бы теоретически взломать что-то вместе, что позволяет при выполнении метода переходить из одного потока в другой 1 .Тем не менее, это было бы не чем иным, как достойным взломом блога, но я думаю, что это возможно. 2

Следующий лучший вариант - перейти на Async.CTP .Эта функция будет доступна в C # и позволит вам делать именно то, что вы просите.Это достигается элегантно с помощью предлагаемого ключевого слова await и некоторых хитрых подвигов, которые также будут включены.Конечный результат будет выглядеть примерно так:

public async void SomeMethod()
{ 
  // Do stuff on the calling thread. 

  await ThreadPool.SwitchTo(); // Switch to the ThreadPool.

  // Do stuff on a ThreadPool thread now!

  await MyForm.Dispatcher.SwitchTo(); // Switch to the UI thread.

  // Do stuff on the UI thread now!
}

Это всего лишь один из множества злых крутых приемов, которые вы можете сделать с новым ключевым словом await.


1 Единственный способ фактически внедрить выполнение кода в существующий поток - это если цель специально предназначена для принятия инъекции в виде рабочего элемента.

2 Вы можете увидеть мой ответ здесь за одну такую ​​попытку имитировать ключевое слово await с помощью итераторов.Платформа MindTouch Dream является еще одним, возможно, лучшим вариантом.Дело в том, что должно быть возможно переключение потоков с помощью какого-то гениального взлома.

2 голосов
/ 09 августа 2011

не легко.

Если вы структурируете свой делегат как конечный автомат, вы можете отслеживать время выполнения между состояниями и, когда вы достигнете желаемого порога, запустить следующее состояние в новом потоке.

Более простым решением было бы запустить его в новом потоке для начала.Любая причина, по которой это неприемлемо?

(отправка сообщений с моего телефона - при необходимости я предоставлю псевдокод, когда буду на реальной клавиатуре)

1 голос
/ 09 августа 2011

Нет, я не думаю, что это возможно. По крайней мере, не напрямую с обычными делегатами. Если вы создали какую-то разновидность IEnumerable, которая дала небольшой результат работы, вы можете вручную выполнить несколько итераций, а затем переключиться на запуск в фоновом потоке после стольких итераций.

Задача ThreadPool и TPL должна быть достаточно производительной, просто всегда запускайте ее в фоновом потоке. Если у вас нет конкретного теста, показывающего, что использование Задачи приводит к накладным расходам, это звучит так, как будто вы пытаетесь преждевременно оптимизировать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...