[C#] 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());

답변

.NET 4.5의 경우 :

Task.Run(() => 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();
    }
}


답변

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

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

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

여기에 이미지 설명을 입력하십시오


답변

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
            }
        });
    }
}

사용 예 :

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

또는 비동기 사용 :

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

이것은 Azure 웹 사이트에서 훌륭하게 작동합니다.

참조 : QueueBackgroundWorkItem을 사용하여 .NET 4.5.2의 ASP.NET 응용 프로그램에서 백그라운드 작업 예약


답변

beginInvoke를 호출하고 EndInvoke를 잡는 것은 좋은 방법이 아닙니다. 대답은 간단합니다. EndInvoke를 호출해야하는 이유는 EndInvoke가 호출 될 때까지 호출 결과 (반환 값이없는 경우에도)가 .NET에 의해 캐시되어야하기 때문입니다. 예를 들어, 호출 된 코드에서 예외가 발생하면 예외가 호출 데이터에 캐시됩니다. EndInvoke를 호출 할 때까지 메모리에 남아 있습니다. EndInvoke를 호출 한 후 메모리를 해제 할 수 있습니다. 이 특정한 경우에, 호출 코드에 의해 데이터가 내부적으로 유지되기 때문에 프로세스가 종료 될 때까지 메모리가 남아있을 수 있습니다. 나는 GC가 결국 그것을 모을지도 모른다고 생각하지만 GC가 데이터를 버렸다는 사실을 어떻게 알지 모르겠다. 나는 그것을 의심한다. 따라서 메모리 누수가 발생할 수 있습니다.

자세한 내용은 http://haacked.com/archive/2009/01/09/asynchronous-fire-and-forget-with-lambdas.aspx 에서 찾을 수 있습니다 .