Ninject с многопоточностью EF - PullRequest
1 голос
/ 04 октября 2019

Доброе утро всем!

Я только начал работать в проекте, где я вижу утечку памяти. Ситуация как ниже. Существует консольное приложение, которое в основном выполняется все время в цикле while(true).

Существует множество классов, которые выполняют некоторую логику в цикле. Каждый класс имеет метод Execute (), где внутри create используется метод Task.Run (), где вызов никем не ожидается. Список вышеперечисленных классов называется Двигатели. Все движки являются классами без сохранения состояния, которые хранятся в массиве в основном классе Program.cs.

Код в основном выглядит следующим образом:

private static List<BaseEngine> Engines;

public static void Main(string[] args)
    {
        InitializeDI();
        RunProgram();
    }
    private static void RunProgram()
    {
        while (true)
        {
            try
            {
                foreach (var engine in Engines)
                {
                    engine.Execute();
                }
            }
            catch (Exception ex)
            {
                //handle
            }
            finally
            {
                Thread.Sleep(TimeSpan.FromSeconds(3));
            }
        }
    }

    private static void InitializeDI()
    {
        _kernel = new StandardKernel();
        ServiceLocator.SetLocatorProvider(() => new NinjectServiceLocator(_kernel));
        NinjectConfig.Setup(_kernel);
    }

Пример двигателя выглядит так:

public class SampleEngine : BaseEngine
        {
            public override void Execute(Task task)
            {
                var someService = ServiceLocator.Current.GetInstance<IDbContext>();

                System.Threading.Tasks.Task.Run(() =>
                {
                    // some action using dbcontext
                });
            }
        }

В приведенном выше примере SampleEngine используется для получения IDbContext из Ninject DI. Однако другие движки могут использовать другие сервисы, зарегистрированные в DI.

Все зависимости зарегистрированы как InCallScope()

По сути, он, как и большинство других движков, связан с пожаром и забывает данный метод с помощью Task.Run. (). Что я сделал, так это изменил метод Execute для возврата Задачи, и после того, как эта задача завершилась до конца, я использовал Dispose() эту задачу. Это не принесло никакой пользы.

Я провел некоторые исследования и увидел, что проблема внутри Ninject.Activation.Cache. Я могу выполнить очистку кеша вручную, что помогает, но я знаю, что проблема где-то в коде, но я не могу найти его.

Поскольку каждая зависимость зарегистрирована как InCallScope (), их следует удалять после начала каждой задачи. Я не вижу ничего, что бы содержало ссылку на эти объекты, потому что каждый движок не имеет состояния.

Я использовал ANTS, чтобы увидеть некоторую информацию, и она просто растет каждую минуту: enter image description here

И это указывает на кэширование Ninject, как показано ниже:

enter image description here

Похоже, DbContext не расположен и все еще существует в кэше Ninject. Это проблема многих задач в системе, или я что-то не так делаю?

Заранее спасибо, ура!

1 Ответ

0 голосов
/ 07 октября 2019

Самым простым подходом, кажется, является встраивание использования в вашу задачу. Но это слепой выстрел, так как кажется, что ваш код упрощен. Вы не используете параметр task в своем методе.

public class SampleEngine : BaseEngine
{
     public override void Execute(Task task)
     {    
       System.Threading.Tasks.Task.Run(() =>
       {
         using (var someService = ServiceLocator.Current.GetInstance<IDbContext>())
         {
           // some action using dbcontext
         }
       });
     }
}

Для более продвинутого подхода, здесь интересная ссылка . Он имеет InTaskScope привязку. Он основан на AsyncLocal и пользовательских задачах с помощью расширений TaskFactory

...