- 공유 링크 만들기
- X
- 이메일
- 기타 앱
이 글의 목적은 Microsoft Excel에서 여러 스레드 계산(Multi-threaded Calculation) 사용 시 간헐적으로 발생하는 충돌·멈춤·응답없음 문제를 체계적으로 진단하고 재발을 방지하는 실무 절차를 제공하는 것이다.
1. 증상 정의와 영향 범위 파악
다중 스레드 계산 충돌은 보통 다음과 같은 형태로 나타난다.
- 계산 중 “응답 없음” 상태가 수십 초 이상 지속되다가 복구되거나 강제 종료되다.
- 재계산(Automatic/Manual) 전환 시 예기치 않은 크래시가 발생하다.
- 동일 통합문서에서 PC에 따라 재현되거나, 동일 PC에서도 간헐적으로 재현되다.
- 동적 배열(스필), 휘발성 함수, 사용자 정의 함수(UDF), 실시간 데이터(RTD), 외부 링크가 섞여 있을 때 빈도가 높아지다.
영향 범위를 먼저 구분해야 한다.
| 구분 | 확인 질문 | 의미 |
|---|---|---|
| 파일 한정 | 특정 통합문서에서만 발생하나? | 수식·UDF·모델 구조 문제 가능성이 높다. |
| 프로필 한정 | 다른 OS 사용자·계정에서도 동일하나? | Excel 전역 옵션·애드인·드라이버 영향 가능성이 있다. |
| 환경 의존 | 코어 수·RAM·버전이 다르면 빈도가 변하나? | 멀티스레드 설정·하드웨어 가속·CPU 마이크로코드 영향 가능성이 있다. |
2. 멀티 스레드 계산 옵션 정확히 설정하기
Excel의 다중 스레드 계산 옵션 위치는 버전에 따라 경로가 다르다. 두 경로를 모두 확인한다.
- 파일 > 옵션 > 수식에서 “다중 스레드 계산 사용(Enable multi-threaded calculation)”과 “스레드 수”를 설정하다.
- 파일 > 옵션 > 고급 > 수식 섹션에서도 동일 항목이 제공되는 경우가 있다.
권장 초기값은 다음과 같다.
- 사용: 체크함.
- 스레드 수: “이 컴퓨터의 모든 프로세서 사용”이 기본이다.
3. 빠른 분리 진단(AB 테스트) 절차
- 안전 모드:
Win + R→excel /safe실행 후 재현을 시도하다. 재현되지 않으면 애드인 또는 개인용 매크로가 원인일 가능성이 높다. - 애드인 차단: COM 애드인, Excel 애드인(.xlam), XLL을 모두 비활성화하고 하나씩 활성화하며 재현하다.
- 하드웨어 그래픽 가속: 파일 > 옵션 > 고급에서 “하드웨어 그래픽 가속 사용 안 함”을 체크하고 재현하다.
- 스레드 수 제한: 스레드 수 1로 설정하여 단일 스레드로 재현 여부를 확인하다.
- 계산 체인 재구성:
Ctrl + Alt + Shift + F9로 전체 계산 종속성 그래프를 강제로 재작성하다.
4. 공통 원인 매트릭스
| 원인 | 설명 | 주요 징후 | 대응 |
|---|---|---|---|
| 휘발성 함수 남용 | OFFSET, INDIRECT, TODAY, RAND 등은 변경 전파 범위가 넓다. | 사소한 편집에도 대규모 재계산 발생 | INDEX 기반 참조로 치환, 구조화 참조 사용, 동적 배열 활용 |
| UDF 비스레드 안전 | VBA UDF는 기본적으로 단일 스레드이며, 상태 공유 시 교착·경쟁이 생기다. | UDF 포함 범위에서만 충돌 | 상태 제거, 전역 변수 금지, XLL로 마이그레이션, 재진입 안전 설계 |
| RTD/외부 연결 | RTD 서버·쿼리가 계산 타이밍과 충돌하다. | 네트워크 변동 시 급증 | RTD 업데이트 간격 조정, 오프라인 캐시, 계산 이벤트 분리 |
| 원형 참조+반복 계산 | Iterative Calculation이 여러 스레드와 맞물려 수렴이 불안정하다. | 값이 진동하거나 수렴 시간이 길다 | 모델 재구성, 수렴 기준·최대 반복 제한 재설정 |
| 동적 배열 스필 충돌 | 스필 영역과 다른 수식이 경합하다. | #SPILL! 간헐 발생 | 스필 영역 확보, LET/TAKE/CHOOSECOLS로 중간 단계 분리 |
| 애드인 경쟁 | 여러 애드인이 계산 이벤트에 동시에 개입하다. | 안전 모드에서 재현 안 됨 | 문제 애드인 격리·업데이트·대체 |
| 대용량 공동 편집/AutoSave | 클라우드 저장소 동기화와 계산 타이밍 충돌 | 저장 순간 멈춤 | AutoSave 임시 해제 후 저장 주기 수동 관리 |
5. 수식·모델 구조 안정화 체크리스트
- 휘발성 최소화: OFFSET→INDEX, INDIRECT→INDEX/XLOOKUP+구조화 참조로 대체하다.
- 의존성 분리: 계산 단계별 시트를 분리하고 스필 범위를 안정적으로 확보하다.
- 중복 계산 제거: LET, LAMBDA로 중간 결과를 재사용하다.
- 데이터 타입 고정: 텍스트 숫자 혼용을 TEXTSPLIT/-- 이중 단항 등으로 정규화하다.
- 정렬/필터 후 참조: SORT/FILTER 결과를 별도 버퍼 범위로 고정하여 경쟁을 줄이다.
6. VBA UDF의 스레드 안전 설계
VBA는 본질적으로 단일 스레드로 실행되며 재입력이 안전하지 않다. 다음 원칙을 따른다.
- 전역 변수, 정적 변수 사용을 피하고 순수 함수로 작성하다.
- 셀 서식 변경, 시트 쓰기 등 부작용을 금지하다.
- Application.Volatile 사용을 최소화하고 명시적 입력만 의존하다.
- 필요 시 계산 모드를 일시 수동으로 전환하고 종료 시 원복하다.
' 비재진입·부작용 없는 UDF 예시 Option Explicit
' 순수 계산: 입력만으로 결과를 결정
Public Function SafeSumProduct(ByVal rngA As Range, ByVal rngB As Range) As Double
Dim i As Long, n As Long
n = Application.WorksheetFunction.Min(rngA.CountLarge, rngB.CountLarge)
Dim a As Variant, b As Variant
a = rngA.Value2: b = rngB.Value2
Dim acc As Double
For i = 1 To n
acc = acc + CDbl(a(i, 1)) * CDbl(b(i, 1))
Next i
SafeSumProduct = acc
End Function
7. XLL(C/C++) UDF의 멀티스레드 대응
C/C++ XLL을 사용한다면 다음을 확인하다.
- 스레드 안전한 라이브러리·알고리즘 사용, 전역 객체 보호 또는 제거
- 메모리 할당·해제는 호출 경계 명확화, 스레드별 컨텍스트 분리
- 오류 시 E# 코드 반환과 예외 전파 금지
- RTD, 외부 I/O는 계산 스레드와 분리하여 비동기 큐로 처리
// Pseudo-code: 스레드 로컬 컨텍스트 thread_local Context tls;
extern "C" __declspec(dllexport)
double __stdcall SafeUdf(double* x, int n) {
// 로컬 상태만 사용
double acc = 0.0;
for (int i = 0; i < n; ++i) acc += x[i];
return acc;
}
8. 계산 모드·스레드 수를 VBA로 제어
재현 테스트 자동화를 위해 다음 매크로를 활용하다.
Sub SetCalcThreads(ByVal useAll As Boolean, ByVal threads As Long) With Application .ScreenUpdating = False .Calculation = xlCalculationAutomatic With .MultiThreadedCalculation .Enabled = True If useAll Then .ThreadCount = .ThreadCount ' 시스템 최대 유지 Else .ThreadCount = Application.WorksheetFunction.Max(1, threads) End If End With .ScreenUpdating = True End With End Sub
Sub RebuildDependencyGraph()
' 전체 계산 체인 강제 재작성
Application.CalculateFullRebuild
End Sub
9. 반복 계산(원형 참조) 안정화
원형 참조가 필요하면 다음 절차를 따른다.
- 파일 > 옵션 > 수식에서 반복 계산을 켜고 최대 반복 횟수와 최대 변경값을 보수적으로 설정하다.
- 스필·외부 참조·UDF와 같은 불확정 요소를 분리하다.
- 수렴 보조: 이전 단계 값 버퍼링, DAMP 적용(혼합률 0.5~0.9) 등으로 진동을 억제하다.
' 간단한 DAMP 적용 예 '=λ*신규값 + (1-λ)*이전값 ' λ=0.7 추천 10. 동적 배열 사용 시 충돌 저감
- 스필 영역을 명시적으로 확보하고 차후 입력범위는 다른 열·시트로 분리하다.
- 대규모 스필은 단계별로 나누고 LET로 중간 산출을 캐시하다.
- 필요 시
@암시적 교차를 의도적으로 사용해 스칼라화하다.
11. RTD·외부 데이터와 계산 타이밍 분리
RTD나 외부 쿼리가 자주 업데이트되면 계산 스레드와 경합한다.
- RTD 업데이트 주기 완화 또는 일시 중지 후 일괄 계산 트리거로 전환하다.
- Power Query로 원천 데이터 스냅샷을 만든 뒤 모델 계산에 사용하다.
- Workbook_Open, Worksheet_Calculate 이벤트에서의 과도한 작업을 제거하다.
12. 저장소·공동 편집 환경 최적화
- 대용량 파일은 AutoSave를 끄고 단계 저장을 수행하다.
- 버전 기록이 많은 파일은 새 통합문서로 “값만 복사” 후 수식 단계적으로 재도입하다.
- 클라우드 동기화 충돌을 줄이기 위해 임시로 로컬 경로에서 테스트하다.
13. 성능·안정성 측정 루틴
측정 가능한 기준이 있어야 개선 효과를 검증할 수 있다.
Sub BenchMarkCalc() Dim t As Double Application.CalculateFullRebuild t = Timer Application.CalculateUntilAsyncQueriesDone Application.CalculateFull Debug.Print "Full Calc(sec) = " & Format(Timer - t, "0.000") End Sub 동일 시나리오에서 스레드 수 1, 2, 4, 최대로 각각 측정하여 최적점을 선택하다.
14. 이벤트·매크로 충돌 진단 포인트
Application.EnableEvents가 False로 남지 않도록On Error블록에서 복구 코드를 넣다.- Calculate/Change 이벤트에서
Calculate호출을 중첩하지 않다. - 타이머 루프·DoEvents 남용을 제거하다.
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range) On Error GoTo ExitHandler Application.EnableEvents = False ' 처리... ExitHandler: Application.EnableEvents = True End Sub 15. 크래시 재현과 로그 수집
- 이벤트 뷰어: Windows 로그 > 응용 프로그램에서 Excel 오류 이벤트를 저장하다.
- 신뢰성 모니터: 검색 > 신뢰성 기록 보기 열고 충돌 패턴을 확인하다.
- MiniDump: 조직 정책 허용 시 WER 설정으로 덤프 수집을 활성화하다.
- 재현 스크립트: 계산 옵션·스레드 수 변경과 전체 재계산을 순서대로 수행하는 매크로를 포함한 최소 재현 파일을 만든다.
16. 단계별 해결 로드맵
- 격리: 안전 모드, 애드인 오프, 스레드=1로 재현 확인하다.
- 구조개선: 휘발성 제거, UDF 순수화, 스필 안정화, 반복 계산 수렴 보정하다.
- 자원제어: 스레드 수 최적화, 하드웨어 가속 토글, AutoSave 정책 조정하다.
- 검증: 벤치마크 매크로로 시간과 재현율을 기록하고 비교하다.
- 배포: 표준 옵션과 애드인 버전을 문서화하여 팀에 배포하다.
17. 현장 점검 체크리스트(인쇄용)
| # | 점검 항목 | 기준 | 상태 |
|---|---|---|---|
| 1 | 다중 스레드 사용 | 사용, 스레드 수 최적점 반영 | □ |
| 2 | 휘발성 함수 제거 | OFFSET/INDIRECT 미사용 | □ |
| 3 | UDF 순수성 | 전역상태·부작용 없음 | □ |
| 4 | RTD/외부연결 관리 | 주기 제한·비동기 분리 | □ |
| 5 | 반복 계산 안정화 | 수렴 보장·DAMP 적용 | □ |
| 6 | 스필 충돌 제거 | 스필 영역 확보 | □ |
| 7 | 애드인 검증 | 문제 애드인 격리 | □ |
| 8 | 그래픽 가속 | 안정 모드와 동일 결과 | □ |
| 9 | 전체 재계산 테스트 | F9/FullRebuild 통과 | □ |
| 10 | 벤치마크 기록 | 시간·재현율 기록 | □ |
18. 현업 팁과 안전장치
- 스냅샷 저장: 크고 복잡한 모델은 단계별 버전을 남겨 회귀를 빠르게 발견하다.
- 테스트 프로필: 동일 파일을 다른 PC·프로필에서 교차 검증하여 환경 요인을 빠르게 배제하다.
- 문서화: 옵션, 애드인 목록, UDF 목록, 데이터 원천을 한 장에 정리하여 인수인계 시간을 단축하다.
FAQ
스레드 수를 늘리면 항상 빨라지나?
그렇지 않다. 의존성이 높은 체인, I/O 대기, UDF 비스레드 안전, RTD 혼재 환경에서는 임계 이상에서 오히려 지연이 늘어날 수 있다. 측정 후 최적점을 선택해야 한다.
VBA UDF도 병렬로 실행되나?
일반적으로 아니다. VBA 런타임은 단일 스레드로 동작하다. XLL 또는 외부 연산 서버로 포팅해야 멀티스레드 이점이 있다.
원형 참조가 있어도 다중 스레드를 켜도 되나?
가능하다. 다만 수렴 보장이 우선이다. 최대 반복·최대 변경값을 보수적으로 설정하고, 스필·외부 연결·UDF와 분리하여 수렴을 안정화해야 한다.
동적 배열을 많이 쓰면 충돌이 늘어나나?
설계에 따라 다르다. 스필 영역 충돌과 대량 재계산이 겹치면 불안정해질 수 있다. 스필 영역을 확보하고 중간 계산을 LET로 캐시하면 안정화된다.
하드웨어 가속을 끄면 언제 도움이 되나?
그래픽 드라이버 문제로 창 그리기와 계산 스케줄링이 간섭할 때 효과가 있다. 재현 테스트에서 차이를 확인한 뒤 정책화한다.