C#의 Resource Pool (리소스 풀)

C# 언어를 활용하여 스레드를 통해 코드를 동시에 실행하고자 하는데, DB Connection과 같은 유한한 자원을 미리 생성해 놓고 활용하고자 합니다. 이때 사용할 리소스 풀로써 만든 클래스입니다.

class ResourcePool<T>
{
    private readonly ConcurrentBag<T> _items = new ConcurrentBag<T>();
    private ManualResetEvent _event = new ManualResetEvent(true);

    public ResourcePool(List<T> items) {
        var iter = items.GetEnumerator();

        while(iter.MoveNext())
        {
            _items.Add(iter.Current);
        }
    }

    public void Release(T item)
    {
        _items.Add(item);
        _event.Set();
    }

    public T Get()
    {
        T item;

        do
        {
            if (_items.IsEmpty)
            {
                _event.Reset();
                _event.WaitOne();
            }
        } while (!_items.TryTake(out item));
            
        return item;
    }
}

위의 ResourcePool은 generic 클래스로 어떤 객체 타입이든 리소스로써 담아두고 활용할 수 있습니다. 예를 들어, 아래와 같은 클래스로 말입니다.

class Resource
{
    public int v {
        get;
        set;
    }

    private int _useCount = 0;

    public Resource(int v)
    {
        this.v = v;
    }

        
    public void increaseUsingCount()
    {
        _useCount++;
    }

    public string toString()
    {
        return "V: " + v + " Count: " + _useCount;
    }
}

이 리소스 풀에 스레드에서 사용할 리소스를 담아두는 코드의 예는 아래와 같습니다.

List<Resource> items = new List<Resource>() { new Resource(0), new Resource(1), new Resource(2), new Resource(3) };
ResourcePool<Resource> objPool = new ResourcePool<Resource>(items);

실제 리소스 풀은 스레드를 통해 활용될 때에 그 의미가 있습니다. 예를 들어 앞서 작성한 코드들을 전제로 아래의 코드처럼 말입니다.

Parallel.For(1, 50, new ParallelOptions { MaxDegreeOfParallelism = 8 },
    (int i) => {
        Resource r = objPool.Get();

        r.increaseUsingCount();
        Console.WriteLine("[Thread-Index: " + i + "] " + r.toString());

        // Some Operation
        Thread.Sleep(new Random().Next(600, 3000));
        // .

        objPool.Release(r);
    });

위의 코드는 총 49개의 스레드를 만들고, MaxDegreeOfParallelism에서 지정한 값이 8만큼, 최대 8개의 스레드만을 동시에 실행하도록 하며, 람다 함수를 통해 실행할 스레드 코드를 지정하고 있습니다.

C#에서 PostgreSQL 사용하기

C# 언어에서 PostgreSQL 데이터베이스를 사용하기 위한 내용을 정리해 봅니다.

먼저 Visual Studio를 실행하고 C# 프로젝트를 생성합니다. 그리고 Package Manager를 실행하는데, 아래와 같은 메뉴를 통해 접근이 가능합니다.

Package Manager는 콘솔창과 비슷한 방식으로 명령을 실행할 수 있는데, .NET을 위한 PostgreSQL 라이브러리를 설치하기 위해 아래의 명령을 입력합니다.

Install-Package Npgsql -Version 4.0.4

현재 시점에서는 4.0.4가 최신버전이지만 이를 확인하기 위해 아래의 URL로 접속하기 바랍니다.

https://www.nuget.org/packages/Npgsql/

라이브러리의 설치가 성공적으로 마무리 되면 아래처럼 코드를 입력하여 PostgreSQL에 대한 조회가 가능합니다.

using (var conn = new NpgsqlConnection("host=localhost;username=postgres;password=__________;database=postgres"))
{
    try
    {
        conn.Open();
        using (var cmd = new NpgsqlCommand())
        {
            cmd.Connection = conn;

            cmd.CommandText = 
                "SELECT table_name " +
                "FROM information_schema.tables " + "" +
                "WHERE table_schema = 'public' AND table_type = 'BASE TABLE'";


            using (var reader = cmd.ExecuteReader())
            {
                while (reader.Read())
                {
                    listBox1.Items.Add(reader.GetString(0));
                    //or listBox1.Items.Add(reader["table_name"].ToString());
                }
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
}

Using 절에 추가해야 할 것은 다음과 같습니다.

using Npgsql;

끝으로 Npgsql은 하나의 Connection에 대해서 하나의 Command만을 실행할 수 있습니다. 확인한 날짜는 2019년 10월 2일자이며, 이 시점에서 최신 버전으로 테스트해 보았습니다.