Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Tip

이장에서 추가적으로 알게되는것

  1. 단순한 문자열이 아닌 객체를 전송하는 방법 ( 자동 시리얼라이즈가 됩니다. )
  2. 액터를 스레드프로그래밍없이 확장하고 분배하는방법 ( 대표적인 라운드 로빈풀을 샘플로 사용하였으며,다양한 라우터를 활용할수 있습니다.)
  3. 동시성 처리를 위한 스레드 모델과 액터모델의 차이점

프린터 기능 요약

  • 출력 완료 소요되는 시간은 페이지에 따라 하드웨어의 성능에 영향받습니다.
  • 출력 완료에 상관없이 프린터 요청은 계속 받을수 있으며 , 순차적으로 프린팅을 합니다. ( 요청에대한 순차 처리)
  • 출력 요청응답은 출력 완료시간 의존없이 즉각 이루어 져야하며 , 대기가 없습니다. 

...

위기능은 DB에 비동기 로그를 쌓는 용도 , Redis에 비동기적인 Write 기능수행등 다양하게 변종이 가능합니다.


프린터 액터 설계

  •    : 완료를 기달려야하는 요청
  •  : 완료를 기달릴 필요없는 요청
  • PrinterController : 프린터에 명령을 실행하는 API
  • PrinterActor : 실제 메시지를 받고 프린터 명령을 수행하는 액터

...

프린팅중이더라도 , 프린터 액터가 메시지를 받을수 있다란것은 수신 메시지 큐가 별도로 작동함을 의미합니다.


프린팅 요청 메시지 구현

Code Block
languagec#
themeEmacs
    public class PrintPage
    {
        public int SeqNo { get; set; }
        
        public int DelayForPrint { get; set; }  //프리팅에 걸리는 시간 조작

        public string Content { get; set; }

        public override string ToString()
        {
            return $"SeqNo:{SeqNo} Content:{Content}";
        }
    }

...

액터를 통해 가상의 프린팅기능을 구현하고 있기때문에, 프린팅에 걸리는 시간조작 기능을 넣어두었습니다. 


프린터 액터 구현

Code Block
languagec#
themeEmacs
public class PrinterActor : ReceiveActor
    {
        private readonly ILoggingAdapter logger = Context.GetLogger();
        private readonly string id;

        public PrinterActor()
        {
            id = Guid.NewGuid().ToString();
            logger.Info($"프린터 액터 생성:{id}");
            
			// 스위치문이 아닌, 메시지 Type에따른 분기처리를 생성자에서 셋팅하는것이
			// 패턴 매칭이라고도 불립니다.  ( ex> 어떠한 type에 특정 조건이 들어왔을때 )
			// 더 다양한 메시지 기능을 추가하고 싶을때 아래와같은 형택의 코드를 Type별로 추가하면 됩니다.
			// 아래 함수는 델리게이트에 등록되며,생성시마다 호출되는것이 아니고 메시지가 올때마다 호출됩니다.
            ReceiveAsync<PrintPage>(async page =>
            {
                logger.Debug($"프린터 요청 들어옴:{page}");
                await Task.Delay(page.DelayForPrint);
                logger.Debug($"페이지 출력 완료:{page}");
            });            
        }
    }

...

여러 언어로 스위칭이 잦고 ,변환되어야할경우 저 수준의 언어 스펙을 선호 하기도합니다. 


프린터 액터 컨트롤러

Code Block
languagec#
themeEmacs
    [Route("api/[controller]")]
    [ApiController]
    public class PrinterController : Controller
    {
        private IActorRef printerActor;

        public PrinterController()
        {
            printerActor = AkkaLoad.ActorSelect("printer")
        }

        // POST api/values
        [HttpPost]
        public void Post([FromBody] PrintPage value)
        {
            // 프린팅을 요청한다.
            printerActor.Tell(value);
        }        
    }

...

이 API는 블락이 없음으로 즉각 반환됩니다.


프린터 액터 객체 생성

Code Block
languagec#
themeEmacs
AkkaLoad.RegisterActor(
	"printer", //여기서 지정한 네이밍은,편리하게 액터 참조를 얻어내기위해 커스텀하게 작성된 네이밍입니다.
	actorSystem.ActorOf(Props.Create<PrinterActor>()
			.WithRouter(new RoundRobinPool(1)),
			"printerActor" // 이 네이밍은 액터시스템내에 고유한 액터명입니다.(공식)
));

...

동시에 N 개를 처리하는 프린터의 구성이 가능하게 됩니다.


스레드 모델과 비교한 액터모델의 특성

지금까지 설명한 코드를 스레드 모델로  동일하게 구현한다고 가정해봅시다.

...

추가 참고 문서 : https://getakka.net/articles/intro/what-problems-does-actor-model-solve.html


프린터 작동하기

출력 명령은 API를 통해 가능하며, 페이지 한장에 출력되는 시간을 3초(3000) 로 셋팅을 하였으며,  로그에서는 동시성 처리를 위한 몇가지 정보를 출력합니다. ( 코드 참고)

...