Как инициализировать REngine глобально в C#.net ?

#c# #r #r.net

#c# #r #r.net

Вопрос:

Я использую R.Net и пакеты R.Net.Community в моем проекте c #, чтобы включить R script. У меня есть класс c # следующим образом:

 foreach(var item in list)
{
  callR(item);
}
  

и метод в другом классе для запуска R script:

 CallR(int item)
{
   //init the R engine                             
                REngine.SetEnvironmentVariables();
                engine = REngine.GetInstance();
                engine.Initialize();

  //Perform R
                engine.SetSymbol("data", item);
                engine.Evaluate("data<-data*data");

//engine.dispose
//Cannot use engine.dispose as re initialization of engine then, is not possible 
}
  

Редактировать
У меня есть еще один третий класс, который вызывает тот же метод R. Если я создам его экземпляр в классе, в котором я создал цикл, то как использовать эту инициализацию в этом классе?

Проблема: этот код отлично работает локально, однако при его развертывании на сервере он прерывается и выдает исключение: «Не удалось загрузить статистику библиотеки».

При более глубоком поиске я нашел это, в котором говорится, что многократная инициализация Rengine вызывает эту проблему.

Поэтому мой вопрос заключается в том, как инициализировать Rengine при запуске самого приложения только один раз и использовать его экземпляр в сценариях, подобных моему коду выше?

Ответ №1:

Я думаю, что лучшей практикой было бы использовать однотонный шаблон, что-то вроде этого:

 public class RNetEngine : IDisposable
{
  private bool _disposed;
  private REngine _rEngine;
  private static readonly object Lock = new object();

  private REngine Engine
  {
    get
    {
      if (_rEngine == null)
      {
        lock (Lock)
        {
        if (_rEngine == null)
          {              
            _rEngine = REngine.GetInstance();
          }
        }
      }
      return _rEngine;
    }
  }

  public void Evaluate(string expression)
  {
    Engine.Evaluate(expression);
  }

  public void Dispose()
  {
    Dispose(true);
    GC.SuppressFinalize(this);
  }

  protected virtual void Dispose(bool disposing)
  {
    if (_disposed)
    {
      return;
    }
    if (disposing)
    {
      if (_rEngine != null amp;amp; !_rEngine.Disposed)
      {
        _rEngine.Dispose();
      }
    }
    _disposed = true;
  }
}
  

Это обеспечит потокобезопасность и утилизацию при необходимости. Я использовал это с Castle.Виндзорский одноэлементный образ жизни, поэтому он не статичен.

Комментарии:

1. Я ценю ваш ответ, но я думаю, что после удаления REngine не может быть повторно инициализирован. Источник: author-entry17.rssing.com/chan-9456546/all_p63.html

2. Правильно, но поскольку это однотональный файл, он не будет удален во время работы приложения, и после этого вам нужно освободить использованные ресурсы.

3. О, хорошо, я не знал об этом .. Спасибо за помощь. Обязательно попробую.

Ответ №2:

Вы можете изменить класс CallR, чтобы иметь один экземпляр класса REngine и получать его с помощью метода, который инициализирует его только один раз, например

 public static REngine engine = null;
        public static REngine GetInitiazedREngine()
        {
            if (engine==null)
            {
                REngine.SetEnvironmentVariables();
                engine = REngine.GetInstance();
                engine.Initialize();
            }
            return engine;
        }

CallR(int item)
{
   //Get the initialized R Engine                             
                REngine initializedEngine=GetInitiazedREngine();

  //Perform R
                initializedEngine.SetSymbol("data", item);
                initializedEngine.Evaluate("data<-data*data");

//engine.dispose
//Cannot use engine.dispose as re initialization of engine then, is not possible 
}