Widziałem w WCF, że mają [OperationContract(IsOneWay = true)]
atrybut. Jednak funkcja WCF wydaje się być powolna i ciężka, aby utworzyć funkcję nieblokującą. Idealnie byłoby coś takiego jak nieblokująca się statyczna pustkaMethodFoo(){}
, ale nie sądzę, że istnieje.
Jaki jest najszybszy sposób utworzenia wywołania metody nieblokującej w języku C #?
Na przykład
class Foo
{
static void Main()
{
FireAway(); //No callback, just go away
Console.WriteLine("Happens immediately");
}
static void FireAway()
{
System.Threading.Thread.Sleep(5000);
Console.WriteLine("5 seconds later");
}
}
NB : Każdy, kto to czyta, powinien pomyśleć o tym, czy rzeczywiście chce, aby metoda została zakończona. (Zobacz pierwszą odpowiedź nr 2) Jeśli metoda musi się zakończyć, w niektórych miejscach, takich jak aplikacja ASP.NET, będziesz musiał zrobić coś, aby zablokować i utrzymać wątek przy życiu. W przeciwnym razie mogłoby to doprowadzić do „odpalenia-zapomnienia-ale-nigdy-nie-wykonania-wykonania”, w którym to przypadku oczywiście łatwiej byłoby napisać w ogóle żaden kod. ( Dobry opis tego, jak to działa w ASP.NET )
źródło
(new Action(FireAway)).BeginInvoke()
Task.Factory.StartNew(() => myevent());
na odpowiedź stackoverflow.com/questions/14858261/ ...W przypadku języka C # 4.0 i nowszych wydaje mi się, że najlepszą odpowiedzią jest teraz Ade Miller: Najprostszy sposób wykonania polecenia odpal i zapomnij w języku c # 4.0
źródło
FireAway
?Task.Factory.StartNew(() => FireAway(foo));
.Task.Factory.StartNew(() => FireAway(foo));
foo nie można modyfikować w pętli, jak wyjaśniono tutaj i tutajW przypadku platformy .NET 4.5:
źródło
Task.Factory.StartNew(() => FireAway(), CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
według blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspxAby dodać do odpowiedzi Willa , jeśli jest to aplikacja konsolowa, po prostu wrzuć an
AutoResetEvent
i a,WaitHandle
aby zapobiec zamknięciu go przed zakończeniem wątku roboczego:źródło
WaitOne
zawsze blokuje iAutoResetEvent
zawsze będzie działaćWaitHandle
s, każda z własnąAutoResetEvent
i odpowiadającą jejThreadPool.QueueUserWorkItem
. Po prostuWaitHandle.WaitAll(arrayOfWaitHandles)
.Prostym sposobem jest utworzenie i uruchomienie wątku z bezparametrową lambdą:
Używając tej metody w ThreadPool.QueueUserWorkItem, możesz nazwać nowy wątek, aby ułatwić debugowanie. Nie zapomnij także o zastosowaniu obszernej obsługi błędów w swojej procedurze, ponieważ wszelkie nieobsłużone wyjątki poza debugerem nagle spowodują awarię aplikacji:
źródło
Zalecanym sposobem zrobienia tego, gdy używasz Asp.Net i .Net 4.5.2, jest użycie
QueueBackgroundWorkItem
. Oto klasa pomocnicza:Przykład użycia:
lub używając async:
Działa to świetnie w witrynach sieci Web platformy Azure.
Dokumentacja: Używanie QueueBackgroundWorkItem do planowania zadań w tle z aplikacji ASP.NET w .NET 4.5.2
źródło
Wywołanie funkcji beginInvoke bez przechwytywania EndInvoke nie jest dobrym podejściem. Odpowiedź jest prosta: Powodem, dla którego powinieneś wywołać EndInvoke, jest to, że wyniki wywołania (nawet jeśli nie ma wartości zwracanej) muszą być buforowane przez .NET do momentu wywołania EndInvoke. Na przykład, jeśli wywołany kod zgłasza wyjątek, wyjątek jest buforowany w danych wywołania. Dopóki nie wywołasz EndInvoke, pozostanie w pamięci. Po wywołaniu EndInvoke pamięć może zostać zwolniona. W tym konkretnym przypadku możliwe jest, że pamięć pozostanie do zakończenia procesu, ponieważ dane są utrzymywane wewnętrznie przez kod wywołania. Wydaje mi się, że GC może w końcu je zebrać, ale nie wiem, skąd GC wiedziałby, że porzuciłeś dane, a ich odzyskanie zajmuje naprawdę dużo czasu. Wątpię, że tak. Dlatego może wystąpić wyciek pamięci.
Więcej można znaleźć na http://haacked.com/archive/2009/01/09/asynchronous-fire-and-forget-with-lambdas.aspx
źródło
BeginInvoke
zwróci obiekt opakowania, który zawiera odniesienie do obiektu, który przechowuje rzeczywiste dane wynikowe, ale do niego się nie odwołuje, obiekt opakowania będzie kwalifikował się do finalizacji, gdy wszystkie odniesienia do niego zostaną porzucone.Prawie 10 lat później:
Dodałbym obsługę wyjątków i logowanie w FireAway
źródło
Najprostszym podejściem .NET 2.0 i nowszym jest użycie Asynchnonous Programming Model (tj. BeginInvoke na delegacie):
źródło
Task.Run()
był to prawdopodobnie najbardziej zwięzły sposób na zrobienie tego.