스레드가 계속 실행되도록하는 동안 함수 호출을 지연시키는 멋진 간단한 방법이 있습니까?
예 :
public void foo()
{
// Do stuff!
// Delayed call to bar() after x number of ms
// Do more Stuff
}
public void bar()
{
// Only execute once foo has finished
}
타이머와 이벤트 처리기를 사용하여이 작업을 수행 할 수 있다는 것을 알고 있지만이를 달성하는 표준 C # 방법이 있는지 궁금합니다.
누군가 궁금하다면, 이것이 필요한 이유는 foo ()와 bar ()가 예외적 인 상황에서 서로를 호출해야하는 다른 (싱글 톤) 클래스에 있기 때문입니다. 문제는 이것이 초기화시 수행되므로 foo는 생성되는 foo 클래스의 인스턴스가 필요한 bar를 호출해야합니다. 따라서 foo가 완전히 인스턴스화되었는지 확인하기 위해 bar ()에 대한 지연된 호출이 필요합니다. 거의 디자인이 안좋아!
편집하다
나쁜 디자인에 대한 요점을 조언하에 드리겠습니다! 나는 시스템을 개선 할 수있을 것이라고 오랫동안 생각했지만,이 끔찍한 상황 은 예외가 발생했을 때만 발생하고 다른 모든 경우에는 두 개의 싱글 톤이 매우 잘 공존합니다. 나는 불쾌한 비동기 패턴을 엉망으로 만들지 않고 클래스 중 하나의 초기화를 리팩터링 할 것이라고 생각합니다.
답변
최신 C # 5/6 덕분에 🙂
public void foo()
{
Task.Delay(1000).ContinueWith(t=> bar());
}
public void bar()
{
// do stuff
}
답변
나는 이것과 같은 것을 찾고 있었다-나는 타이머를 사용하지만 초기 지연을 위해 한 번만 사용하고 어떤 Sleep
전화도 필요로하지 않지만 다음을 생각해 냈습니다 .
public void foo()
{
System.Threading.Timer timer = null;
timer = new System.Threading.Timer((obj) =>
{
bar();
timer.Dispose();
},
null, 1000, System.Threading.Timeout.Infinite);
}
public void bar()
{
// do stuff
}
( 콜백 내에서 타이머를 처리하는 아이디어에 대해 Fred Deschenes 에게 감사드립니다 )
답변
이전 댓글 작성자의 설계 관찰에 동의하는 것 외에는 나에게 충분한 솔루션이 없었습니다. 닷넷 4 제공 Dispatcher
및 Task
실행을 지연 만든다 클래스 현재 스레드에 아주 간단합니다 :
static class AsyncUtils
{
static public void DelayCall(int msec, Action fn)
{
// Grab the dispatcher from the current executing thread
Dispatcher d = Dispatcher.CurrentDispatcher;
// Tasks execute in a thread pool thread
new Task (() => {
System.Threading.Thread.Sleep (msec); // delay
// use the dispatcher to asynchronously invoke the action
// back on the original thread
d.BeginInvoke (fn);
}).Start ();
}
}
맥락을 위해, 나는 이것을 사용하여 ICommand
UI 요소에서 왼쪽 마우스 버튼에 묶인 것을 디 바운스합니다 . 사용자는 모든 종류의 혼란을 일으키는 더블 클릭을합니다. (나는 Click
/ DoubleClick
핸들러를 사용할 수도 있다는 것을 알고 있지만 ICommand
전반적 으로 s 와 함께 작동하는 솔루션을 원했습니다 ).
public void Execute(object parameter)
{
if (!IsDebouncing) {
IsDebouncing = true;
AsyncUtils.DelayCall (DebouncePeriodMsec, () => {
IsDebouncing = false;
});
_execute ();
}
}
답변
이러한 객체의 생성 제어와 상호 의존성은 클래스 자체가 아닌 외부에서 제어해야하는 것처럼 들립니다.
답변
싱글 톤 자체가 나쁜 디자인은 말할 것도없고 실제로 매우 나쁜 디자인입니다.
그러나 실제로 실행을 지연해야하는 경우 수행 할 수있는 작업은 다음과 같습니다.
BackgroundWorker barInvoker = new BackgroundWorker();
barInvoker.DoWork += delegate
{
Thread.Sleep(TimeSpan.FromSeconds(1));
bar();
};
barInvoker.RunWorkerAsync();
그러나 이것은 bar()
별도의 스레드 에서 호출 됩니다. bar()
원래 스레드에서 호출해야하는 경우 bar()
호출을 RunWorkerCompleted
핸들러 로 이동 하거나 SynchronizationContext
.
답변
글쎄, 나는 “디자인”요점에 동의해야 할 것이다. 그러나 당신은 아마 모니터를 사용하여 다른 하나가 중요한 섹션을 지나면 알릴 수있을 것이다.
public void foo() {
// Do stuff!
object syncLock = new object();
lock (syncLock) {
// Delayed call to bar() after x number of ms
ThreadPool.QueueUserWorkItem(delegate {
lock(syncLock) {
bar();
}
});
// Do more Stuff
}
// lock now released, bar can begin
}
답변
public static class DelayedDelegate
{
static Timer runDelegates;
static Dictionary<MethodInvoker, DateTime> delayedDelegates = new Dictionary<MethodInvoker, DateTime>();
static DelayedDelegate()
{
runDelegates = new Timer();
runDelegates.Interval = 250;
runDelegates.Tick += RunDelegates;
runDelegates.Enabled = true;
}
public static void Add(MethodInvoker method, int delay)
{
delayedDelegates.Add(method, DateTime.Now + TimeSpan.FromSeconds(delay));
}
static void RunDelegates(object sender, EventArgs e)
{
List<MethodInvoker> removeDelegates = new List<MethodInvoker>();
foreach (MethodInvoker method in delayedDelegates.Keys)
{
if (DateTime.Now >= delayedDelegates[method])
{
method();
removeDelegates.Add(method);
}
}
foreach (MethodInvoker method in removeDelegates)
{
delayedDelegates.Remove(method);
}
}
}
용법:
DelayedDelegate.Add(MyMethod,5);
void MyMethod()
{
MessageBox.Show("5 Seconds Later!");
}
