Есть ли стандартный способ реализации проприетарного пула соединений в .net? - PullRequest
5 голосов
/ 19 июля 2009

Существует ли стандартная модель пула соединений (или API), аналогичная той, которая используется поставщиками данных в .net , которую я мог бы использовать для реализации своего собственного пула соединений?

Я спрашиваю, потому что у меня есть требование реализовать свой собственный пул соединений для проприетарного устройства TCP / IP, которое мы используем в веб-сервисе. В настоящее время проблема заключается в том, что существует большое количество подключений (читай слишком много) к устройству из-за многопоточной природы веб-служб, работающих под IIS. Я хочу ограничить количество этих соединений, используя свой собственный пул соединений, и, кажется, глупо изобретать велосипед, если есть стандартная модель, которую я мог бы использовать для этого.

Ответы [ 3 ]

6 голосов
/ 19 июля 2009

Существует ли стандартная модель пула подключений

Кроме ADO.NET, нет. Но модель ADO.NET довольно проста. Создайте объект для получения соединения из пула или создания заново, и он возвращается в пул при закрытии / удалении / финализации.

Из этого можно сразу определить шаблон реализации:

  • Тип клиента является прокси для реального типа и имеет время жизни от создания до Закрыть / & hellip ;. Это прокси для реального объекта. Предоставляет методы и свойства, которые жду реального соединения.
  • Реальное соединение - это долгоживущий экземпляр, созданный пулом, выданным через прокси а затем вернулся в конце прокси.

В реализации есть выбор. Когда объект был выдан, должен ли пул также сохранять ссылку? Если это так, пул должен отслеживать, какие объекты активны, а какие объединены; в противном случае можно использовать простой набор доступных объектов.

Что-то вроде:

internal class MyObjectImpl {
  // The real object that holds the resource
}

internal static class MyObjectPool {
  private static object syncRoot = new object();
  private static Queue<MyObjectImpl> pool = new Queue<MyObject>();
  private static int totalObjects = 0;
  private readonly int maxObjects = 10;

  internal MyObjectImplGet() {
    lock (syncRoot) {
      if (pool.Count > 0) {
        return pool.Dequeue();
      }
      if (totalOjects >= maxObjects) {
        throw new PoolException("No objects available");
      }
      var o = new MyObjectImpl();
      totalObjects++;
      return o;
    }
  }

  internal void Return(MyObjectImpl obj) {
    lock (syncRoot) {
      pool.Enqueue(obj);
    }
  }
}

public class MyObject : IDisposable {
  private MyObjectImpl impl;

  public MyObject() {
    impl = MyObjectPool.Get();
  }

  public void Close() {
    Dispose();
  }

  public void Dispose() {
    MyIObjectPool.Return(impl);
    // Prevent continuing use, as the implementation object instance
    // could now be given out.
    impl = null;
  }

  // Forward API to imp

}

Это не учитывает случаи уничтожения MyObject. Например. хранить коллекцию слабых ссылок на выделенные MyObject и, если пул пуст, проверять удаленные экземпляры. Это также понадобится, если вы не можете рассчитывать на то, что клиент закроет или удалит экземпляры, или внедрите финализатор на MyObjectImpl 1 (и сообщите об этом как об ошибке в отладочных сборках).

1 Это невозможно сделать с MyObject, поскольку к моменту завершения MyObject экземпляр MyObjectImpl уже мог быть завершен.

4 голосов
/ 19 июля 2009

Обновление

На самом деле теперь я знаю больше, думаю, я бы использовал функцию из моего контейнера IoC на выбор - Castle Windsor . Один из встроенных образов жизни - это « pooled », что означает, что всякий раз, когда вы запрашиваете у контейнера объект, зарегистрированный в этом образе жизни, он дает вам объекты в пуле, если это возможно, или же создайте новый.

Раньше ...

Я думаю, что вы хотите реализовать "пул объектов". Вот несколько вещей, которые выглядели многообещающими:

Конечно, с вашими объектами в пуле, вы должны быть осторожны с параллелизмом, синхронизацией потоков и т. Д.


Для соединений с базой данных:

Вы можете контролировать количество соединений в пуле соединений .NET с помощью опции в строке соединения: «максимальный размер пула», как описано в: http://msdn.microsoft.com/en-us/library/8xx3tyca(VS.71).aspx

Старайтесь избегать реализации своего собственного, если можете.

0 голосов
/ 19 июля 2009

Методы веб-службы должны быть без сохранения состояния (т. Е. Между вызовами не поддерживается никаких объектов на сервере). То, что вы хотите сделать, - это поддерживать коллекцию проприетарных объектов соединений на сервере между вызовами и выделять существующие объекты соединений из этого пула для каждого вызова метода (вместо создания нового объекта соединения в каждом методе).

Простой способ сделать это - объявить вашу коллекцию объектов как "частную статическую" в рамках вашего веб-сервиса, но вне области любого метода, например:

public class Service1 : System.Web.Services.WebService
{
    private static List<CustomConnection> _connections = 
        new List<CustomConnection>();

    [WebMethod]
    public string HelloWorld()
    {
        return "Hello World";
    }
}

и затем заполните коллекцию из события запуска веб-службы (я не помню, что это за событие в данный момент - я вернусь с ним через секунду). Любой метод, которому необходимо использовать соединение, получит объект соединения из этого списка вместо создания нового (вам придется обрабатывать метод выделения соединений и помечать их как «используемые» и т. Д.).

Это будет работать нормально, если ваш веб-сервис вызывается часто (веб-сервисы обычно отключаются после 20 минут бездействия, что потребует перестройки пула соединений для следующего вызова). Если вам нужно поддерживать свою коллекцию подключений, прочитайте эту статью:

http://msdn.microsoft.com/en-us/library/system.web.httpapplicationstate.aspx

...