Programing

C #에서 화재를 피하고 방법을 잊는 가장 간단한 방법은 무엇입니까?

crosscheck 2020. 6. 28. 18:33
반응형

C #에서 화재를 피하고 방법을 잊는 가장 간단한 방법은 무엇입니까?


WCF에서 [OperationContract(IsOneWay = true)]속성이 있습니다. 그러나 WCF는 비 차단 기능을 만들기 위해 느리고 무겁습니다. 이상적으로는 static void nonblocking과 같은 것이 MethodFoo(){}있지만 나는 존재하지 않는다고 생각합니다.

C #에서 비 차단 메서드 호출을 만드는 가장 빠른 방법은 무엇입니까?

예 :

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 :이 글을 읽는 모든 사람들이 실제로 방법을 끝내기를 원한다면 생각해야합니다. (# 2 상위 답변 참조)이 방법을 완료해야하는 경우 ASP.NET 응용 프로그램과 같은 일부 위치에서 스레드를 활성 상태로 유지하고 차단할 수있는 작업을 수행해야합니다. 그렇지 않으면 이로 인해 "불을 잊었지만 결코 실제적으로 실행되지 않을"수 있습니다. 물론 코드를 전혀 작성하지 않는 것이 더 간단합니다. ( 이것이 ASP.NET에서 어떻게 작동하는지에 대한 좋은 설명 )


ThreadPool.QueueUserWorkItem(o => FireAway());

(5 년 후...)

Task.Run(() => FireAway());

luisperezphd가 지적한 대로 .


C # 4.0 이상에서는 Ade Miller가 최고의 답변을 얻었습니다 .C # 4.0에서 가장 쉬운 방법은 화재를 잊고 방법을 잊는 것입니다.

Task.Factory.StartNew(() => FireAway());

또는...

Task.Factory.StartNew(FireAway);

또는...

new Task(FireAway).Start();

어디 FireAway있다

public static void FireAway()
{
    // Blah...
}

따라서 클래스 및 메소드 이름 간결성으로 인해 선택한 문자에 따라 스레드 풀 버전이 6 ~ 19 자 사이입니다. :)

ThreadPool.QueueUserWorkItem(o => FireAway());

Will의 답변에 추가하려면 콘솔 응용 프로그램 인 경우 작업자 스레드가 완료되기 전에 AutoResetEventa 및 a WaitHandle던져 종료되지 않도록하십시오.

Using System;
Using System.Threading;

class Foo
{
    static AutoResetEvent autoEvent = new AutoResetEvent(false);

    static void Main()
    {
        ThreadPoolQueueUserWorkItem(new WaitCallback(FireAway), autoEvent);
        autoEvent.WaitOne(); // Will wait for thread to complete
    }

    static void FireAway(object stateInfo)
    {
        System.Threading.Thread.Sleep(5000);
        Console.WriteLine("5 seconds later");
        ((AutoResetEvent)stateInfo).Set();
    }
}

.NET 4.5의 경우 :

Task.Run(() => FireAway());

쉬운 방법은 매개 변수가없는 람다로 스레드를 만들고 시작하는 것입니다.

(new Thread(() => { 
    FireAway(); 
    MessageBox.Show("FireAway Finished!"); 
}) { 
    Name = "Long Running Work Thread (FireAway Call)",
    Priority = ThreadPriority.BelowNormal 
}).Start();

ThreadPool.QueueUserWorkItem에서이 메소드를 사용하면 디버깅하기 쉽게 새 스레드의 이름을 지정할 수 있습니다. 또한 디버거 외부에서 처리되지 않은 예외가 발생하면 응용 프로그램이 갑자기 중단되므로 루틴에서 광범위한 오류 처리를 사용하는 것을 잊지 마십시오.

enter image description here


Asp.Net 및 .Net 4.5.2를 사용할 때 권장되는 방법은을 사용하는 것 QueueBackgroundWorkItem입니다. 헬퍼 클래스는 다음과 같습니다.

public static class BackgroundTaskRunner
{     
    public static void FireAndForgetTask(Action action)
    {
        HostingEnvironment.QueueBackgroundWorkItem(cancellationToken => // .Net 4.5.2 required
        {
            try
            {
                action();
            }
            catch (Exception e)
            {
                // TODO: handle exception
            }
        });
    }

    /// <summary>
    /// Using async
    /// </summary>
    public static void FireAndForgetTask(Func<Task> action)
    {
        HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken => // .Net 4.5.2 required
        {
            try
            {
                await action();
            }
            catch (Exception e)
            {
                // TODO: handle exception
            }
        });
    }
}

Usage example:

BackgroundTaskRunner.FireAndForgetTask(() =>
{
    FireAway();
});

or using async:

BackgroundTaskRunner.FireAndForgetTask(async () =>
{
    await FireAway();
});

This works great on Azure Web Sites.

Reference: Using QueueBackgroundWorkItem to Schedule Background Jobs from an ASP.NET Application in .NET 4.5.2


Calling beginInvoke and not catching EndInvoke is not a good approach. Answer is simple: The reason that you should call EndInvoke is because the results of the invocation (even if there is no return value) must be cached by .NET until EndInvoke is called. For example if the invoked code throws an exception then the exception is cached in the invocation data. Until you call EndInvoke it remains in memory. After you call EndInvoke the memory can be released. For this particular case it is possible the memory will remain until the process shuts down because the data is maintained internally by the invocation code. I guess the GC might eventually collect it but I don't know how the GC would know that you have abandoned the data vs. just taking a really long time to retrieve it. I doubt it does. Hence a memory leak can occur.

More can be found on http://haacked.com/archive/2009/01/09/asynchronous-fire-and-forget-with-lambdas.aspx


Almost 10 years later:

Task.Run(FireAway);

I would add exception handling and logging inside FireAway


The simplest .NET 2.0 and later approach is using the Asynchnonous Programming Model (ie. BeginInvoke on a delegate):

static void Main(string[] args)
{
      new MethodInvoker(FireAway).BeginInvoke(null, null);

      Console.WriteLine("Main: " + Thread.CurrentThread.ManagedThreadId);

      Thread.Sleep(5000);
}

private static void FireAway()
{
    Thread.Sleep(2000);

    Console.WriteLine("FireAway: " + Thread.CurrentThread.ManagedThreadId );  
}

참고URL : https://stackoverflow.com/questions/1018610/simplest-way-to-do-a-fire-and-forget-method-in-c

반응형