Почему моя задача выполняется медленно при использовании Task.Result, но быстро, когда я использую await TaskC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Почему моя задача выполняется медленно при использовании Task.Result, но быстро, когда я использую await Task

Сообщение Anonymous »

Когда я запускаю приведенный ниже код как часть своего приложения, заменяя строку «var емкостьScenarios = debouncer.Result;» следующей строкой: «var емкостьScenarios = await debouncer;» приводит к значительному увеличению производительности. Разница во времени выполнения составляет около 3 минут, и эта сумма увеличивается по мере увеличения количества дней/потоков.
Я заметил это, потому что мы только недавно включили некоторую асинхронную функциональность в некоторые ранее существовавшие классы. Таким образом, вместо того, чтобы настраивать все классы вверх по дереву для возврата Task в определенные моменты, я просто выполнял .Wait или .Result для задачи.
Я знаю, что .Wait или .Result удерживает поток, а также создает новый для выполнения задачи, но я не понимаю, как это приводит к таким резким колебаниям выполнения. Делаю ли я что-то не так где-нибудь в своей логике, что могло бы объяснить это?
Изменить: мой класс отладчика просто останавливает вызов, который в идеале принимает перечисляемое в качестве входных данных, чтобы группа потоков могла индивидуально выполнять вызовы к нему, и после некоторого периода ожидания исходный вызов будет выполнен с соответствующим образом агрегированным перечисляемым (вместо разовых вызовов). Средство устранения дребезжания заставляет каждый вызывающий поток ожидать выполнения одной задачи, поэтому каждый поток завершается одновременно после завершения работы средства устранения дребезжания. Я включил его сюда, чтобы каждый мог сам продемонстрировать медлительность и увидеть лежащий в основе дизайн на случай, если это повлияет на какие-либо предложения по улучшению дизайна.
public void SlowOrFastFunction(){
var tasks = new List();
for (int i = 0; i < 500; i++)
{
var date = DateTime.Now.AddDays(i);
var task = Task.Run(async () =>
{
var debouncer = Debouncer.Debounce("Simulation", 3000, date, (input) =>
{
return input;
}, (inputs) =>
{
return inputs.Select(i =>
{
return i
}).ToArray();
});
//var capacityScenarios = await debouncer;
var capacityScenarios = debouncer.Result;
});
tasks.Add(task);
}
Task.WaitAll(tasks.ToArray());
}

public static class Debouncer
{
static ConcurrentDictionary _taskTimeInputDictionary = new();
static ConcurrentDictionary _processLockDictionary = new();
public async static Task Debounce(string uniqueKey, int milliseconds, inputT input, Func inputAggregator, Func action, bool singleThreaded = false, ILogger? logger = null)
{
Task task = null;
var processLockDictionary = _processLockDictionary.GetOrAdd(uniqueKey + $"_ProcessLock {(singleThreaded ? "_ST" : "")}", new Tuple(new object(), DateTime.Now));
var processLock = processLockDictionary.Item1;
_processLockDictionary.TryUpdate(uniqueKey + $"_ProcessLock {(singleThreaded ? "_ST" : "")}", new Tuple(processLock, DateTime.Now), processLockDictionary);
lock (processLock)
{
var dictionaryRecord = _taskTimeInputDictionary.AddOrUpdate(uniqueKey + "_Task",
(key) => //key not found - create new
{
logger?.LogInformation("Adding dictionary record for " + uniqueKey);
return new Tuple(null, DateTime.Now.AddMilliseconds(milliseconds), new List() { input });
},
(key, tt) =>
{
tt.Item3.Add(input);
return new Tuple(tt.Item1, DateTime.Now.AddMilliseconds(milliseconds), tt.Item3);
}
);
if (dictionaryRecord.Item1 == null)
{
Task temptask = BuildTask(uniqueKey, inputAggregator, action, singleThreaded, logger, processLock);
_taskTimeInputDictionary.TryUpdate(uniqueKey + "_Task", new Tuple(temptask, dictionaryRecord.Item2, dictionaryRecord.Item3), dictionaryRecord);
task = temptask;
}
else
{
task = dictionaryRecord.Item1 as Task;
}
}
//await Task.Delay(10000);
return await task;
//await Task.Delay(milliseconds);
//return default(T);
}

private static Task BuildTask(string uniqueKey, Func inputAggregatorFunc, Func processFunc, bool singleThreaded, ILogger? logger, object processLock)
{
try
{
return TimedExecutor(uniqueKey, inputAggregatorFunc, processFunc, singleThreaded, processLock, logger);
}
catch (Exception ex)
{
logger?.LogError("Error triggering timed executor. Returning Null: " + ex);
return Task.FromResult(default(T));
}
}

private static Task TimedExecutor(string uniqueKey, Func inputAggregatorFunc, Func processFunc, bool singleThreaded, object processLock, ILogger? logger)
{
aggregatorOutput input = default(aggregatorOutput);
bool Run;
DateTime executeTime;

var dictionaryRecord = _taskTimeInputDictionary[uniqueKey + "_Task"];
executeTime = dictionaryRecord.Item2;
Run = DateTime.Now > executeTime;

if (Run)
{
lock (processLock)
{
_taskTimeInputDictionary.Remove(uniqueKey + "_Task", out dictionaryRecord);
input = inputAggregatorFunc(dictionaryRecord.Item3.Select(i => (inputT)i).ToList());
logger?.LogInformation("Executing debouncer action for " + uniqueKey + ". Removing dictionary record.");
//Clean up process lock dictionary
_processLockDictionary.Where(i =>
{
var accessDiff = DateTime.Now.Ticks - i.Value.Item2.Ticks;
var remove = TimeSpan.FromTicks(accessDiff) > TimeSpan.FromHours(2);
return remove;
}).ForEach(i =>
{
_processLockDictionary.TryRemove(i.Key, out _);
});
}
if (singleThreaded && Run)
{
try
{
try
{
var result = processFunc(input);
return Task.FromResult(result);
}
catch (Exception ex)
{
logger?.LogError("Error executing debouncer action. Returning null from action: " + ex);
return Task.FromResult(default(T));
}
}
catch (Exception ex)
{
throw;
};
}
}
if (!singleThreaded && Run)
{
try
{
var result = processFunc(input);
return Task.FromResult(result);
}
catch (Exception ex)
{
logger?.LogError("Error executing debouncer action. Returning null from action: " + ex);
return Task.FromResult(default(T));
}
}

return Task.Run(async () =>
{
await Task.Delay(25);
return await BuildTask(uniqueKey, inputAggregatorFunc, processFunc, singleThreaded, logger, processLock);
});
}
}


Подробнее здесь: https://stackoverflow.com/questions/784 ... await-task
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»