Стоимость производительности при использовании перегрузки IAsyncResult для Task.FromAsync - PullRequest
6 голосов
/ 11 июня 2011

Я пытаюсь обернуть некоторые существующие вызовы APM (BeginX, EndX) в Tasks, чтобы получить все их преимущества.К сожалению, наши методы неординарны и используют параметры out и поэтому не могут использовать стандартный метод FromAsync, в котором вы предоставляете ему как начальный, так и конечный делегаты и позволяете ему красиво обернуть его.

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

Это выглядело нормально, но потом я прочитал еще одну статью об упаковке вызовов APM в задачи ,Он также упоминает, что перегрузка IAsyncResult не так эффективна, как другие методы.Мне кажется, что это означает, что обратный вызов не используется, чтобы сообщить о завершении метода.Это означает, что они должны использовать AsyncWaitHandle или опрос IsCompleted.Какой из них они используют?Сколько это снижает производительность?

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

Кто-нибудь знает, что они делают и каксуровое ли это снижение производительности?

Ответы [ 4 ]

1 голос
/ 25 июля 2012

Прибыл сюда, потому что у меня была похожая проблема (с параметрами out), но только по методу End. Вот то, что я придумал, это может быть полезно кому-то:

var provider = new Provider();
return Task<Whatever>.Factory.FromAsync(provider.Begin, ar =>
{
    Whatever outparam;
    provider.End(out outparam);
    return outparam;
}, state);

Компилируется:)

1 голос
/ 11 июня 2011

Кто-нибудь знает, что они делают и насколько серьезен этот штраф за производительность?

Это не невероятно серьезно, но есть дополнительные накладные расходы.Поскольку вы не предоставляете им ту же информацию (только IAsyncResult), реализация должна вызвать ThreadPool.RegisterWaitForSingleObject , чтобы вызвать обратный вызов после завершения IAsyncResult.

Когдаэто не используется, и существует пара обратного вызова «Начало / Конец + обратный вызов», обратный вызов автоматически может инициировать завершение задачи, исключая при этом дополнительный ожидающий вызов.Это эффективно связывает поток ThreadPool с блоком (WaitOne) на дескрипторе ожидания до завершения операции.Если это редкое явление, производительность может быть незначительной, но если вы делаете это lot , это может быть проблематично.

1 голос
/ 11 июня 2011

Глядя на код в JustDecompile, он создает TaskCompletionSource, обертывающий IAsyncObject, который создает новую задачу, что, вероятно, означает поток, ожидающий завершения IAsyncObject. Не идеально, но это, вероятно, единственный способ сделать это, поскольку нет способа сделать хороший опрос на один размер для всех.

0 голосов
/ 11 июня 2011

Когда вы передаете ISyncResult, TaskFactory не может вставить обратный вызов.Поэтому TaskFactory нужно, чтобы ISynResult запускал WaitHandle, и нужен ThreadPool, чтобы получить поток, ожидающий этого дескриптора.В опросе нет участия.

...