Как узнать, когда действительно начинается асинхронный вызов?
-
06-07-2019 - |
Вопрос
Я хочу иметь возможность измерять время, необходимое для выполнения асинхронного метода.
Когда я вызываю метод синхронно, я запускаю следующий код и получаю точное количество времени, которое потребовалось методу MyMethod.
for (int i = 0; i < 5000; i++) {
stopWatches[i].Start();
webService.MyMethod(new Request());
stopWatches[i].Stop();
}
Я изменил свой код для асинхронного выполнения MyMethod, поэтому теперь мой код выглядит следующим образом.
var callback = new Action<IAsyncResult>(ar => {
int i = (int)ar.AsyncState;
try {
var response = webService.EndMyMethod(ar);
stopWatches[i].Stop();
}
}
for (int i = 0; i < 5000; i++) {
webService.BeginMyMethod(new Request(), new AsyncCallback(callback), i);
stopWatches[i].Start();
}
Проблема в том, что секундомеры больше не измеряют время, необходимое для выполнения запроса.Они измеряют время с момента поступления запроса в очередь ThreadPool до окончания вызова.В итоге я получаю список секундомеров, время в которых растет линейно.
Как починить секундомеры?Есть ли способ точно узнать, когда начнется запрос?
Спасибо!
ОБНОВЛЯТЬ:Я не могу изменить реализацию MyMethod.
Решение
Создайте метод BeginTimedMyMethod не в классе веб-сервиса.В реализации BeginTimedMyMethod вместо MyMethod вызовите промежуточный метод, который вызывается асинхронно.Запустите там секундомер, затем вызовите MyMethod.
void BeginTimedMyMethod(...)
{
//create delegate with StartMethod as target
//Invoke StartMethod delegate
}
void StartTimedMethod(Request request)
{
stopWatches[i].Start();
webservice.MyMethod(request);
}
Другие советы
Что именно вы пытаетесь сделать с измерениями?Фактически вы измеряете фактическое количество времени, которое проходит с момента запроса на выполнение какой-либо работы до ее завершения.Кажется, это имеет смысл.Как до, так и после переключения кода вы измеряете фактическую задержку запроса.
Похоже, вы пытаетесь настроить аспект вокруг класса mymethod.Самый простой способ сделать это — использовать среду АОП, такую как PostSharp.Что вы создаете что-то вроде
public class MyStopWatchContext
{
Stopwatch _watch = new Stopwatch();
public void OnMethodEntry()
{
_watch.Start();
}
public void OnMethodExit()
{
_watch.End();
Debug.Print(_watch.Duration);
}
}
Затем внутри вашего класса с помощью вашего метода у вас есть
public class MyService
{
[MyStopWatchContext]
public void SomeServiceMethod()
{ ...
}
}
Это позволит вам связать этот аспект с методом без необходимости его модификации.Однако вам все равно потребуется перекомпилировать код там.Таким образом, это должно быть жизнеспособно, даже если этот класс является просто прокси-сервером для внешней службы, которую вы не можете контролировать, поскольку вы должны иметь возможность просто разместить этот аспект поверх прокси-вызова.