в настоящее время у меня есть следующий цикл foreach
foreach (var formId in formIdList)
{
var hasAccess = Task.Run(async () => await _userAccessService.HasAccessToFormId(formId)).Result;
if (!hasAccess)
{
throw new UnauthorizedAccessException();
}
}
пытаясь выяснить, как сделать больше задачи. когда все виды конструкции, чтобы все функции могли работать параллельно, и если какой-либо из них возвращает false для var hasaccess, то генерирует несанкционированное исключение.
/ ************************* обновленный вопрос для токена отмены ************
используя решение jstewards ниже. немного не уверен, как использовать токен отмены (прошу прощения, я больше являюсь разработчиком интерфейса, поэтому здесь я немного не в своем элементе)
как использовать токен для отмены запущенных задач?
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
var formIdList = AttributeRequestHelper.GetFormIdList(filterContext.ActionArguments);
CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
Task.Run(async () => await CheckIds(formIdList),token);
}
public async Task CheckIds(IEnumerable<int> formIdList)
{
var results = formIdList.Select(id => _userAccessService.HasAccessToFormId(id)).ToList();
while (results.Any())
{
var result = await Task.WhenAny(results);
results.Remove(result);
var authorized = await result;
if (!authorized) throw new UnauthorizedAccessException();
}
}
да короткое замыкание было бы даже лучше
@RossBush Почему именно WithDegreeOfParallelism (6)? Как правило, нет необходимости указывать количество используемых потоков, поскольку TPL определит наилучшее количество необходимых потоков.
@ckuri - Вы правы, однако есть несколько крайних случаев, особенно при смешивании длинных вызовов доступа к базе данных, которые могут заставить TPL думать, что выполняется меньше работы, и объединять больше потоков, чем идеально.
Вы можете немного сократить это как formIdList.AsParallel (). ForAll (formId => {}
@ckuri Я удалил свой предыдущий комментарий и добавил один, удаляющий WithDegreeOfParallelism, так как это может вызвать путаницу.
Рассматривали ли вы возможность передать массив в HasAccessToFormId и позволить вашей базе данных делать тяжелую работу вместо того, чтобы забивать ее отдельными запросами?
@RossBush Разве PLINQ ForAll не выполняет только действия, а не Func<Task<bool>>?
@JSteward - Да, и если вам нужно полностью выйти из строя, исключение остановит только последующие спауны, вам все равно понадобится схема отмены / обратного вызова, чтобы остановить уже запущенные потоки. Я неправильно истолковал вопрос.





Как насчет этого, он бросит на первый неавторизованный идентификатор. Однако здесь нет возможности отменить другой запрос, поэтому они просто игнорируются. Я бы посоветовал поработать в CancellationToken, чтобы отменить другие задачи, поскольку вас не волнуют их результаты и, по крайней мере, await их завершение.
public async Task CheckIds(IEnumerable<int> formIdList)
{
var results = formIdList.Select(id => _userAccessService.HasAccessToFormId(id)).ToList();
while (results.Any())
{
var result = await Task.WhenAny(results);
results.Remove(result);
var authorized = await result;
if (!authorized) throw new UnauthorizedAccessException();
}
}
спасибо, я обновил свой вопрос, ища разъяснений по токену отмены (извините, я больше являюсь разработчиком интерфейса, поэтому здесь немного не в моей тарелке)
@BryanDellinger, чтобы отменить, вам нужно будет полностью передать токен через HasAccessToFormId до фактического вызова API. Затем, когда вы хотите отменить, вызовите отмену в источнике токена отмены. Дополнительная информация
о, думаю, я не могу пойти по этому пути, так как у меня нет доступа к api
Не api, вам просто нужно побеспокоиться о вызове api с вашей стороны
Вы бы предпочли вариант с «коротким замыканием», когда произойдет первый отказ? Или вы хотите подождать, пока все не закончатся, прежде чем выбросить исключение?