본문 바로가기

개발일지/C#

[C#] Random.Next()로 1/5 확률 선택하기 – 퍼센트(%) 조건 제어

 

(조회 프로그램 제작시) 보통은 조회 후 결과값이 없을 때 'E' 또는 그에 준하는 형태로 상태 변경이 되면서 처리 대상에서 제외가 된다.

 

여기서 -끝-

 

 

... 이 아니라 일정 시간이 지나면서 별도의 등록이 이뤄진 그~~~ 이후~~~~ 결과값이 생긴다. 고거슬 재조회 하게 되면, 새롭게 접수된 신청건들과 동시에 처리 대상에 포함이 되게 되는데.... 신규건의 처리가 밀리는 상황은 피해야 하므로, 우선순위를 고려해 1/5(20%)의 확률로 제외 건들을 선별해 재조회 할 수 있도록 조회 쿼리를 짠다. 

 

예시는 모두 테스트 컬럼명을 이용하고 있음.

 

1) 변경 전 readYn이 'R'인 데이터만 조회하던 방식

        public static String getSelectServiceId(String pc_id, String deviceId) {
            var readYn = "R";

            string sql =
            "SELECT TEST_ID, TEST_NAME, TEST_CODE, TEST_DATE " +
            "FROM TEST_TABLE " +
            "WHERE TEST_DATE BETWEEN TRUNC(SYSDATE - 7) AND TRUNC(SYSDATE) " +
            $"AND TEST_FLAG = '{readYn}' " +
            $"AND DEVICE_ID = '{deviceId}' AND ROWNUM <= 1";

            return sql;
        }

 

 

2) Random.Next() 함수를 이용해 'E'rrer / 'R'eady 상태값 선택 

       public static String getSelectServiceId(String pc_id, String deviceId) {
           var rand = new Random();
           var readYn = (rand.Next(5) == 0) ? "E" : "R";

           string sql =
               "SELECT TEST_ID, TEST_NAME, TEST_CODE, TEST_DATE " +
               "FROM TEST_TABLE " +
               "WHERE TEST_DATE BETWEEN TRUNC(SYSDATE - 7) AND TRUNC(SYSDATE) " +
               $"AND TEST_FLAG = '{readYn}' " +
               $"AND DEVICE_ID = '{deviceId}' AND ROWNUM <= 1";

           return sql;
       }

 

- rand.Next(5)는 0~4 사이의 정수를 반환하기 때문에 5분의 1, 즉 20%의 확률로 E를 반환한다.

- readYn 변수는 () ? true : false 삼항 연산자 참고

 

일반적으로 한 번만 조회하고 끝나는 프로그램은 없을 것이다. 이와 같은 조회 로직은 반복적으로 호출되는 구조로 구성돼 있다. 위 코드처럼 매번 new Random() 생성자를 호출하면, 호출 시점 간 간격이 짧기 때문에 같은 결과가 나오고(짧은 시간 안에 반복해서 실행되기 때문에 같은 수가 나옴), 불필요한 생성자가 반복적으로 생성되므로 메모리 효율도 좋지 않다. 따라서 아래와 같이 static(정적인) 전역변수로 선언한 뒤 프로그램 시작 시 단 한 번만 초기화하여 사용해야 한다. 

 

 

internal static class Program
{
    private static readonly Random rand = new Random();

    public static String getSelectServiceId(String pc_id) {
        // 20% 확률로 E 나머지는 R
        String readYn = (rand.Next(5) == 0) ? "E" : "R";

        return
            "SELECT TEST_ID, TEST_NAME, TEST_CODE, TEST_DATE " +
              "FROM TEST_TABLE " +
             "WHERE TEST_DATE BETWEEN TRUNC(SYSDATE - 7) AND TRUNC(SYSDATE) " +
              $"AND TEST_FLAG = '{readYn}' " +
              $"AND DEVICE_ID = '{deviceId}' AND ROWNUM <= 1";
    }

 


꽤 단순한 패턴이지만 실제로 유용하게 사용되는 방식이다. 우선순위 기반 처리를 설계할 때, 일정 확률로 특정 건을 선별해 처리하는 전략은 전체 시스템의 유연성과 효율성을 높이니까 말이다. 주의해야 할 사항은 인스턴스 초기화는 무조건 단 한 번만 선언을 해야 한다는 점이다.