@Default, für die Verwendung von Sleep () sollte die Aufgabe immer: 1) einen separaten Thread erzeugt haben und 2) nur einen. Nicht weniger und nicht mehr und 3) es kann nicht wiederverwendet werden. Nichts davon gilt für eine Aufgabe. Es ist kein Betrug, bei Ihrem Link geht es darum, den Start einer Aufgabe zu verzögern. Meine Frage ist, es jeden Moment nach seinem Start in den Schlaf zu versetzen
Fulproof
11
Die Verwendung Thread.Sleepin Ihrem Code ist fast immer ein Fehler.
Eli Arbel
Antworten:
60
Mit a können Sie Timereine DelayMethode in 4.0 erstellen :
Vielen Dank, ich habe nicht angegeben, aber ich versuche, meiner WPF-Anwendung Multithreading hinzuzufügen. Soll ich dort das Argument Timer mit Rückruf verwenden? Und in der Callback()Definition verwenden Dispatcher.BeginInvoke()?
Fulproof
@Fulproof Sie führen keine UI-Interaktion durch, wenn der Timer ausgelöst wird. Es gibt also keinen Grund dafür.
Servy
1
Wie füge ich CancellationToken hinzu, das Task.Delay bereitstellt?
Imran Rizvi
2
Schafft dies nicht eine Rennbedingung? Wenn das Timer-Objekt vor Ablauf des Timers Müll sammelt, wird dieser anscheinend TrySetResultnie aufgerufen.
Edward Brey
10
@EdwardBrey Die TimerKlasse behandelt dies speziell intern, um sicherzustellen, dass Benutzer nicht während ihrer gesamten Lebensdauer an einem Verweis darauf festhalten müssen. Solange der Timer gerade ausgeführt wird, fügt er an einem verwurzelten Speicherort einen Verweis auf sich selbst hinzu und entfernt ihn dann, wenn er nicht mehr ausgeführt wird.
Ich habe das Beispiel zu Ihrer Antwort hinzugefügt, falls der Link aus irgendeinem Grund nicht mehr funktioniert.
Standard
2
@Fulproof Er schrieb, dass er LinqPad verwendet, das eine Erweiterungsmethode hinzufügt, die objectden Wert seiner ToStringMethode ausgibt . Beachten Sie, dass er dies und keine anderen Methoden außerhalb der Bibliothek in seiner tatsächlichen Implementierung verwendet, sondern nur die Beispielfunktion, mit der es getestet wird.
Servy
@Servy, danke. Ich habe die Frage gestellt, um die Anzahl der Unbekannten zu verringern (und Antworten zu erhalten), aber keine Rätsel zum Lösen hinzuzufügen. Dh eine Person, die fragt, hat normalerweise kein Fachwissen, um das Rätsel zu
lösen
1
Aktualisiert, so dass Sie einfach kopieren, einfügen und ausführen können)
QrystaL
Sollte der Timer nicht entsorgt werden?
Amit G
6
Unten finden Sie den Code und das Beispielkabel für eine stornierbare Task.Delay-Implementierung. Sie interessieren sich wahrscheinlich für die DelayMethode:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespaceDelayImplementation
{
classProgram
{
staticvoidMain(string[] args)
{
System.Threading.CancellationTokenSource tcs = new System.Threading.CancellationTokenSource();
int id = 1;
Console.WriteLine(string.Format("Starting new delay task {0}. This one will be cancelled.", id));
Task delayTask = Delay(8000, tcs.Token);
HandleTask(delayTask, id);
System.Threading.Thread.Sleep(2000);
tcs.Cancel();
id = 2;
System.Threading.CancellationTokenSource tcs2 = new System.Threading.CancellationTokenSource();
Console.WriteLine(string.Format("Starting delay task {0}. This one will NOT be cancelled.", id));
var delayTask2 = Delay(4000, tcs2.Token);
HandleTask(delayTask2, id);
System.Console.ReadLine();
}
privatestaticvoidHandleTask(Task delayTask, int id)
{
delayTask.ContinueWith(p => Console.WriteLine(string.Format("Task {0} was cancelled.", id)), TaskContinuationOptions.OnlyOnCanceled);
delayTask.ContinueWith(p => Console.WriteLine(string.Format("Task {0} was completed.", id)), TaskContinuationOptions.OnlyOnRanToCompletion);
}
static Task Delay(int delayTime, System.Threading.CancellationToken token)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
if (delayTime < 0) thrownew ArgumentOutOfRangeException("Delay time cannot be under 0");
System.Threading.Timer timer = null;
timer = new System.Threading.Timer(p =>
{
timer.Dispose(); //stop the timer
tcs.TrySetResult(null); //timer expired, attempt to move task to the completed state.
}, null, delayTime, System.Threading.Timeout.Infinite);
token.Register(() =>
{
timer.Dispose(); //stop the timer
tcs.TrySetCanceled(); //attempt to mode task to canceled state
});
return tcs.Task;
}
}
}
Ich denke, die ursprüngliche Idee ist, den aktuellen Thread zu blockieren, nicht auf einen weiteren Thread zu warten und erst später über den aktuellen Thread benachrichtigt zu werden. Wie wäre es damit ?
Alex R.
0
publicstaticvoidDelayExecute(double delay, Action actionToExecute)
{
if (actionToExecute != null)
{
var timer = new DispatcherTimer
{
Interval = TimeSpan.FromMilliseconds(delay)
};
timer.Tick += (delegate
{
timer.Stop();
actionToExecute();
});
timer.Start();
}
}
Das OP fragt nach 4.0 - in 4.0 gibt es kein "Warten".
Alex R.
Das awaitSchlüsselwort ist Teil der C # -Sprache, die von der .NET Framework-Version getrennt ist. Das Problem ist, dass Task<T>es nicht gibt GetAwaiter, worauf es awaitankommt. Microsoft.Bcl.Async liefert dies. Ich habe meine Antwort aktualisiert, um das NuGet-Paket zu erwähnen.
Thread.Sleep
in Ihrem Code ist fast immer ein Fehler.Antworten:
Mit a können Sie
Timer
eineDelay
Methode in 4.0 erstellen :public static Task Delay(double milliseconds) { var tcs = new TaskCompletionSource<bool>(); System.Timers.Timer timer = new System.Timers.Timer(); timer.Elapsed+=(obj, args) => { tcs.TrySetResult(true); }; timer.Interval = milliseconds; timer.AutoReset = false; timer.Start(); return tcs.Task; }
quelle
Callback()
Definition verwendenDispatcher.BeginInvoke()
?TrySetResult
nie aufgerufen.Timer
Klasse behandelt dies speziell intern, um sicherzustellen, dass Benutzer nicht während ihrer gesamten Lebensdauer an einem Verweis darauf festhalten müssen. Solange der Timer gerade ausgeführt wird, fügt er an einem verwurzelten Speicherort einen Verweis auf sich selbst hinzu und entfernt ihn dann, wenn er nicht mehr ausgeführt wird.Verwenden Sie das Microsoft.Bcl.Async- Paket von NuGet
TaskEx.Delay
.quelle
using System; using System.Threading; using System.Threading.Tasks; class Program { static void Main() { Delay(2000).ContinueWith(_ => Console.WriteLine("Done")); Console.Read(); } static Task Delay(int milliseconds) { var tcs = new TaskCompletionSource<object>(); new Timer(_ => tcs.SetResult(null)).Change(milliseconds, -1); return tcs.Task; } }
Aus dem Abschnitt Implementieren von Task.Delay in 4.0
quelle
object
den Wert seinerToString
Methode ausgibt . Beachten Sie, dass er dies und keine anderen Methoden außerhalb der Bibliothek in seiner tatsächlichen Implementierung verwendet, sondern nur die Beispielfunktion, mit der es getestet wird.Unten finden Sie den Code und das Beispielkabel für eine stornierbare Task.Delay-Implementierung. Sie interessieren sich wahrscheinlich für die
Delay
Methode:using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DelayImplementation { class Program { static void Main(string[] args) { System.Threading.CancellationTokenSource tcs = new System.Threading.CancellationTokenSource(); int id = 1; Console.WriteLine(string.Format("Starting new delay task {0}. This one will be cancelled.", id)); Task delayTask = Delay(8000, tcs.Token); HandleTask(delayTask, id); System.Threading.Thread.Sleep(2000); tcs.Cancel(); id = 2; System.Threading.CancellationTokenSource tcs2 = new System.Threading.CancellationTokenSource(); Console.WriteLine(string.Format("Starting delay task {0}. This one will NOT be cancelled.", id)); var delayTask2 = Delay(4000, tcs2.Token); HandleTask(delayTask2, id); System.Console.ReadLine(); } private static void HandleTask(Task delayTask, int id) { delayTask.ContinueWith(p => Console.WriteLine(string.Format("Task {0} was cancelled.", id)), TaskContinuationOptions.OnlyOnCanceled); delayTask.ContinueWith(p => Console.WriteLine(string.Format("Task {0} was completed.", id)), TaskContinuationOptions.OnlyOnRanToCompletion); } static Task Delay(int delayTime, System.Threading.CancellationToken token) { TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(); if (delayTime < 0) throw new ArgumentOutOfRangeException("Delay time cannot be under 0"); System.Threading.Timer timer = null; timer = new System.Threading.Timer(p => { timer.Dispose(); //stop the timer tcs.TrySetResult(null); //timer expired, attempt to move task to the completed state. }, null, delayTime, System.Threading.Timeout.Infinite); token.Register(() => { timer.Dispose(); //stop the timer tcs.TrySetCanceled(); //attempt to mode task to canceled state }); return tcs.Task; } } }
quelle
Erweiterung der Idee aus dieser Antwort :
new AutoResetEvent(false).WaitOne(1000);
quelle
Sie können das Visual Studio Async CTP herunterladen und TaskEx.Delay verwenden
quelle
In vielen Fällen ist ein reines AutoResetEvent besser als ein Thread.Sleep () ...
AutoResetEvent pause = new AutoResetEvent(false); Task timeout = Task.Factory.StartNew(()=>{ pause.WaitOne(1000, true); });
hoffe, dass es hilft
quelle
public static void DelayExecute(double delay, Action actionToExecute) { if (actionToExecute != null) { var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(delay) }; timer.Tick += (delegate { timer.Stop(); actionToExecute(); }); timer.Start(); } }
quelle
Hier ist eine prägnante, zeitgesteuerte Implementierung mit ordnungsgemäßer Bereinigung:
var wait = new TaskCompletionSource<bool>(); using (new Timer(_ => wait.SetResult(false), null, delay, Timeout.Infinite)) await wait.Task;
Um diesen Code unter .NET 4.0 verwenden zu können, benötigen Sie das Microsoft.Bcl.Async NuGet-Paket.
quelle
await
Schlüsselwort ist Teil der C # -Sprache, die von der .NET Framework-Version getrennt ist. Das Problem ist, dassTask<T>
es nicht gibtGetAwaiter
, worauf esawait
ankommt. Microsoft.Bcl.Async liefert dies. Ich habe meine Antwort aktualisiert, um das NuGet-Paket zu erwähnen.TaskEx.Delay
prägnanter?