특정 주기마다 호출되는 코드 만들기 (PeriodicInvoker)
간단하게 특정 주기마다만 호출되는 코드를 만들고 싶었다.
1초마다 호출되는 타이머 같은 기능이다.
반응형
< PeriodicInvoker 코드 >
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Timers; // System.Timers.Timer 사용을 위한 네임스페이스
using UnityEngine;
public class PeriodicInvoker
{
private readonly ConcurrentDictionary<Guid, ScheduledTask> _tasks = new();
private readonly System.Timers.Timer _timer; // System.Timers.Timer 명시적으로 사용
private CancellationTokenSource _cancellationTokenSource = new();
public PeriodicInvoker(double resolutionMilliseconds = 100)
{
if (resolutionMilliseconds <= 0)
throw new ArgumentException("Resolution must be greater than zero.", nameof(resolutionMilliseconds));
_timer = new System.Timers.Timer(resolutionMilliseconds) // System.Timers.Timer 사용
{
AutoReset = true,
Enabled = false
};
_timer.Elapsed += OnElapsed;
}
private void OnElapsed(object? sender, ElapsedEventArgs e)
{
if (_cancellationTokenSource.IsCancellationRequested)
{
Stop();
return;
}
var now = DateTime.UtcNow;
foreach (var taskPair in _tasks)
{
var task = taskPair.Value;
if (now >= task.NextExecutionTime)
{
if (task.CancellationToken.IsCancellationRequested)
{
_tasks.TryRemove(taskPair.Key, out _); // 취소된 작업 제거
continue;
}
try
{
UnityMainThreadDispatcher.Instance().Enqueue(() => task.Callback?.Invoke());
if (task.IsOneTime)
{
_tasks.TryRemove(taskPair.Key, out _); // 한 번만 실행하는 작업은 제거
}
else
{
task.NextExecutionTime = now.AddMilliseconds(task.IntervalMilliseconds);
}
}
catch (Exception ex)
{
Debug.LogError($"Task Execution Error: {ex.Message}");
task.OnError?.Invoke(ex);
}
}
}
}
/// <summary>
/// 주기적 작업을 등록합니다.
/// </summary>
public Guid RegisterTask(double intervalMilliseconds, Action callback, CancellationToken cancellationToken, Action<Exception>? onError = null)
{
if (intervalMilliseconds <= 0)
throw new ArgumentException("Interval must be greater than zero.", nameof(intervalMilliseconds));
if (callback == null)
throw new ArgumentNullException(nameof(callback));
var task = new ScheduledTask
{
IntervalMilliseconds = intervalMilliseconds,
Callback = callback,
OnError = onError,
NextExecutionTime = DateTime.UtcNow.AddMilliseconds(intervalMilliseconds),
IsOneTime = false,
CancellationToken = cancellationToken
};
var id = Guid.NewGuid();
_tasks[id] = task;
return id;
}
/// <summary>
/// 특정 시간 뒤 한 번만 실행되는 작업을 등록합니다.
/// </summary>
public Guid RegisterDelayedTask(double delayMilliseconds, Action callback, CancellationToken cancellationToken, Action<Exception>? onError = null)
{
if (delayMilliseconds <= 0)
throw new ArgumentException("Delay must be greater than zero.", nameof(delayMilliseconds));
if (callback == null)
throw new ArgumentNullException(nameof(callback));
var task = new ScheduledTask
{
IntervalMilliseconds = delayMilliseconds,
Callback = callback,
OnError = onError,
NextExecutionTime = DateTime.UtcNow.AddMilliseconds(delayMilliseconds),
IsOneTime = true,
CancellationToken = cancellationToken
};
var id = Guid.NewGuid();
_tasks[id] = task;
return id;
}
/// <summary>
/// 등록된 작업을 수동으로 제거합니다.
/// </summary>
public void UnregisterTask(Guid taskId)
{
_tasks.TryRemove(taskId, out _);
}
/// <summary>
/// 모든 작업을 취소하고 종료합니다.
/// </summary>
public void CancelAllTasks()
{
_cancellationTokenSource.Cancel();
_tasks.Clear();
}
public void Start() => _timer.Start();
public void Stop() => _timer.Stop();
private void OnDestroy()
{
Dispose();
}
public void Dispose()
{
Stop();
_timer.Dispose();
_cancellationTokenSource.Cancel();
_cancellationTokenSource.Dispose();
_tasks.Clear();
}
private class ScheduledTask
{
public double IntervalMilliseconds { get; set; }
public Action? Callback { get; set; }
public Action<Exception>? OnError { get; set; }
public DateTime NextExecutionTime { get; set; }
public bool IsOneTime { get; set; }
public CancellationToken CancellationToken { get; set; }
}
}
반응형
< 1초마다 호출되는 코드 >
public void PlayStart()
{
timer = new PeriodicInvoker(1000);
timerID = timer.RegisterTask(1000, () =>
{
time ++;
timerAction?.Invoke(time);
}, CancellationToken.None);
timer.Start();
}
< 종료 >
if (timerID != Guid.Empty)
timer.UnregisterTask(timerID);
★☆☆☆☆
반응형
'개발 > Unity' 카테고리의 다른 글
Unity) 백그라운드 실행 옵션 (Run In Background) (3) | 2025.02.22 |
---|---|
Unity) OnGUI Attribute 작업하기 (0) | 2025.02.18 |
Unity) RectTransform 스크린 좌표로 변환해서 위치값 찾기 (0) | 2025.02.12 |
Unity) 2D Grid 만들기 ( 2D Grid ) (0) | 2025.02.04 |
개발) 문자열 검색 필터(*와일드 카드 , 정규식 변환 활용하기) (0) | 2025.01.31 |
댓글