DbContext и задача

Мы наблюдаем некоторые трудно воспроизводимые проблемы, которые, по-видимому, связаны с сервером SQL и тем, как мы с ним взаимодействуем, и я выясняю, можем ли мы использовать DBContext в сочетании с Task неправильно.

У нас есть концентратор signalR, который использовал множество моих клиентов. Когда мы достигаем определенного уровня клиентов, система замедляется, и в конечном итоге все перестает работать.

signalR похож на этот пример, но с гораздо большим количеством асинхронных методов:

namespace Test.Webservice.Hubs
{
    public class ExampleHub : Hub<ExampleClientContract>, IExampleHub
    {
        private readonly ILogger _logger;
        private readonly IExampleRepository _exampleRepo;

        public ExampleHub(ILogger logger, IExampleRepository exampleRepo)
        {
            _logger = logger;
            _exampleRepo = exampleRepo;
        }
        
        public async Task<IEnumerable<ExampleTopicState>> GetExampleStates(Guid operationId)
        {
            var examples = await _exampleRepo.GetExampleStatesAsync(operationId);

            return examples.Select(ExampleTopicState.Create);
        }   
    }
} 

ExampleRepository выглядит примерно так, но опять же с большим количеством методов:

namespace Test.DataAccess.Repository
{
    public class ExampleRepository : IExampleRepository
    {
        private readonly ILogger _logger;
        private readonly ExampleContext _context;
        private readonly IExampleRepositoryMapping _repositoryMapping;

        public ExampleRepository(ILogger logger, IExampleRepositoryMapping repositoryMapping)
        {
            _repositoryMapping = repositoryMapping;
            _logger = logger;
            _context = new ExampleContext();
        }

        public async Task<IEnumerable<ExampleDto>> GetExampleStatesAsync(Guid operationId)
        {
            IEnumerable<Example> result = null;

            await Task.Factory.StartNew(() =>
                                        {
                                            result = _context
                                                     .Examples.Where(c => c.OperationId.Equals(operationId))
                                                     .GroupBy(o => o.Type)
                                                     .SelectMany(p => p.GroupBy(q => q.Topic))
                                                     .Select(o => o.FirstOrDefault(
                                                                 n => n.ExampleTimeUtc == o.Max(d => d.ExampleTimeUtc)));
                                        });

            return _repositoryMapping.Mapper.Map<IEnumerable<ExampleDto>>(result);
        }

    }
}

Правильно ли использовать DbContext внутри ожидания Task.Factory.StartNew или это может привести к проблемам? Этот SO answere кажется, говорит, что это может быть проблематично, но я не уверен, что понимаю это полностью.

Редактировать:

Мысль добавить пример того, как хаб вызывается с одного из клиентов:

    var loadingTasks = _connectorMap.Select(o => (System.Action) ( () =>
                                                                        {
                                                                            var result =  o.Proxy.Invoke<ExampleResult>(
                                                                                "GetExampless",
                                                                                _connectedOperations.Where(c => o.HubConnection.Url.StartsWith(c.ExampleWebService)).Select(s => s.UniqueId),
                                                                                filter.TimeFilter.Start,
                                                                                filter.TimeFilter.End,
                                                                                filter.TopicFilter,
                                                                                filter.SeverityLevelFilter,
                                                                                currentPage, pageSize,
                                                                                filter.IsGrouped).Result;
                                                                            _results.Add(result);
                                                                        }));

    Parallel.ForEach(loadingTasks, lt => lt());

Каков срок службы IExampleRepository (т.е. как он регистрируется в DI)?

devNull 14.12.2020 11:03
Task.Factory.StartNew = "пожалуйста, запустите этот код в каком-нибудь другом потоке для меня, у меня есть другие дела" - await - "У меня нет никакой полезной работы, пока эта другая вещь не будет завершена". Вы видите, как они в основном противоречивы? Если ваш текущий поток не является чем-то особенным, просто запустите код в существующем потоке.
Damien_The_Unbeliever 14.12.2020 11:03

@Damien_The_Unbeliever Хороший вопрос. Может ли это быть причиной проблем, которые мы наблюдаем?

Q-bertsuit 14.12.2020 11:17

@devNull Он зарегистрирован следующим образом: container.Register(Component.For<IExampleRepository>().Imple‌​mentedBy<ExampleRepo‌​sitory>().LifestyleT‌​ransient());

Q-bertsuit 14.12.2020 11:20
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
594
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы просто хотите SelectAsync?

public async Task<IEnumerable<ExampleDto>> GetExampleStatesAsync(Guid operationId)
{
    IEnumerable<Example> result = null;

    var result = await _context
            ...
            .SelectMany(...);
            .Select(...)
            .ToListAsync(); // Fetch from db.
    });

    return _repositoryMapping.Mapper.Map<IEnumerable<ExampleDto>>(result);
}

Полный пример доступен по адресу Асинхронный запрос и сохранение.

Спасибо за это! Как вы думаете, дизайн с использованием Task может привести к проблемам или он просто неэффективен?

Q-bertsuit 14.12.2020 12:09

Я думаю, что наиболее подходящим прилагательным является то, что Task.Factory.StartNew не нужен. Даже в тех случаях, когда нет готового метода (например, ToListAsync), Task.Run — это путь: см. документы:* Начиная с .NET Framework 4.5, метод Task.Run является рекомендуемым запустить задачу, связанную с вычислениями.*

tymtam 14.12.2020 12:29

Кроме того, вы смешивали Task с IEnumerable<T>, что не обязательно неправильно, но, безусловно, может сбивать с толку. StartNew (который должен быть Task.Run) отправляет работу в поток пула потоков, но отталкиваемая работа буквально просто создает запрос, даже не запуская его, потому что IEnumerable<T> выполняется лениво. Использование ToListAsync будет правильно выполнять запрос асинхронно. И тогда поток пула потоков вообще не нужен, так как он уже асинхронный.

Stephen Cleary 15.12.2020 02:37

Оказывается, проблема была где-то еще в коде. Спасибо за указание на проблемные части кода. Очень признателен!

Q-bertsuit 19.12.2020 08:11

@ Стивен Клири Это имеет смысл! Я был сбит с толку тем, почему IEnumeral использовался сам. Это код, написанный разработчиками, которые больше не работают в компании, поэтому спросить об этом не у кого.

Q-bertsuit 19.12.2020 08:13

Другие вопросы по теме