Emacs Lisp에서 비동기 호출 코드 작성하기
그렇게 자주 있는 일은 아니겠지만 이맥스의 UI를 얼려버릴 만큼 무거운 코드를 돌려야 할 일이 있다면 느낌이 어떨까. 이맥스가 얼어버리는 현상은 결코 유쾌하지는 못 할 것이다. 그동안 다른 작업도 못 하고 말이다.
그렇다면 비동기로 호출하면 이런 문제를 해결할 수 있지 않을까? 간단하게 이맥스에서 비동기로 코드를 호출하는 방법을 정리해 보자.
run-with-idle-timer
(run-with-idle-timer 3 nil #'my-function)
run-with-idle-timer
함수는 지정된 시간이 지난 후 이맥스가 쉬는(idle) 도중에 지정한 함수를 비동기로 호출한다.
두 번째 인자는 반복 여부라 원하는 반복 횟수를 적어줄 수도 있다.
run-with-timer
(run-with-timer 3 nil #'my-function)
run-with-timer
함수도 지정된 시간이 지난 후 지정한 함수를 비동기로 호출한다. 다만 이맥스가 쉬든 말든 무작정 호출하는 듯하다.
역시나 두 번째 인자로 반복 횟수를 지정할 수 있다.
async.el
순수하게 비동기 호출만을 생각하고 외부 패키지에 대해 열려있다면(?) async.el 혹은 emacs-async라는 패키지를 사용할 수도 있다. 이 패키지 내의 async-start
함수를 이용할 수 있다고 한다.
참고로 이 항목은 직접 돌려보진 않았고 그저 메모 목적으로 작성한다.
(async-start
(lambda () (my-function))
;; callback
(lambda (result)
(message "Result: %s" result)))
이 async-start
함수는 두 개의 함수를 인자로 넘긴다. 첫 인자가 비동기로 호출할 함수이고 두 번째 인자는 비동기 실행 결과를 받아서 동작하는 함수다. 즉 위의 예의 경우 my-function이라는 함수가 비동기로 호출된 후 이 함수의 결과가 두 번째 인자의 함수에 첫 인자로 전달된다.
만약 결과를 받을 필요가 없다면 무시(ignore) 심볼을 남겨주자.
(async-start
(lambda () (my-function))
'ignore)
쉴 시간 주기
이 항목은 비동기 처리 자체와는 관계가 없지만 약간의 덤이다.
단순 비동기 호출이라도 과도한 작업은 당연하게도 이맥스를 얼려버리는 현상이 나타날 수밖에 없다. 이를 피하기 위해선 비동기 코드의 루프에서 쉴 시간을 조금씩 주는 편이 좋다. 예를 들자면 sleep-for
함수가 있다.
(sleep-for 1) ;; wait for 1 seconds
쉬게만 한다면 위의 코드로도 충분하겠지만 좀 더 깔끔하게(?) 쉬려면 sit-for
를 사용하는 편이 좋다.
(sit-for 1) ;; redisplay and wait for 1 seconds
sit-for
는 sleep-for
와 비슷하지만 화면을 한번 갱신시켜 준다는 점이 특징이다. 그 외에 입력이 가능하게 되면 멈추는 등 비동기 작업 용도로는 sleep-for
에 비해 약간읜 전문적(?)인 느낌이다.
참고로 쉬는 시간은 초(seconds) 단위인데 소수점 단위도 된다. 즉 0.1초나 0.01초 정도로 짧게 쉬는 것도 가능하다.