비동기 식

이 문서에서는 비동기 식에 대한 F#의 지원을 설명합니다. 비동기 식은 다른 작업의 실행을 차단하지 않고 비동기적으로 계산을 수행하는 한 가지 방법을 제공합니다. 예를 들어 비동기 계산을 사용하여 애플리케이션이 다른 작업을 수행할 때 사용자에게 응답하는 기본 UI가 있는 앱을 작성할 수 있습니다. F# 비동기 워크플로 프로그래밍 모델을 사용하면 라이브러리 내에서 스레드 전환의 세부 정보를 숨기면서 기능 프로그램을 작성할 수 있습니다.

.NET 작업을 직접 만드는 작업 식을 사용하여 비동기 코드를 작성할 수도 있습니다. .NET 작업을 만들거나 사용하는 .NET 라이브러리와 광범위하게 상호 운용하는 경우 작업 식을 사용하는 것이 좋습니다. F#에서 대부분의 비동기 코드를 작성하는 경우 F# 비동기 식은 더 간결하고 더 구성적이며 .NET 작업과 관련된 특정 주의 사항을 방지하기 때문에 선호됩니다.

구문

async { expression }

설명

이전 구문에서 나타내는 expression 계산은 비동기적으로 실행되도록 설정됩니다. 즉, 비동기 절전 작업, I/O 및 기타 비동기 작업이 수행될 때 현재 계산 스레드를 차단하지 않고 실행됩니다. 현재 스레드에서 실행이 계속되는 동안 비동기 계산은 백그라운드 스레드에서 시작되는 경우가 많습니다. 식의 형식은 Async<'T>키워드(keyword) 'T 사용할 때 return 식에서 반환되는 형식입니다.

이 클래스는 Async 여러 시나리오를 지원하는 메서드를 제공합니다. 일반적인 방법은 비동기적으로 실행하려는 계산 또는 계산을 나타내는 개체를 만든 Async 다음 트리거 함수 중 하나를 사용하여 이러한 계산을 시작하는 것입니다. 사용하는 트리거는 현재 스레드, 백그라운드 스레드 또는 .NET 작업 개체를 사용할지 여부에 따라 달라집니다. 예를 들어 현재 스레드 Async.StartImmediate에서 비동기 계산을 시작하려면 . UI 스레드에서 비동기 계산을 시작하면 키 입력 및 마우스 작업과 같은 사용자 작업을 처리하는 기본 이벤트 루프를 차단하지 않으므로 애플리케이션이 다시 응답할 기본 있습니다.

let!을 사용하여 비동기 바인딩

비동기 식에서 일부 식과 연산은 동기식이고 일부는 비동기식입니다. 메서드를 비동기적으로 호출하는 경우 일반 let 바인딩 let!대신 . 그 효과는 let! 계산이 수행될 때 다른 계산 또는 스레드에서 실행을 계속할 수 있도록 하는 것입니다. 바인딩의 오른쪽이 let! 반환되면 나머지 비동기 식은 실행을 다시 시작합니다.

다음 코드에서는 차이점과 let!.let 사용하는 코드 let 줄은 비동기 계산을 나중에 사용할 수 있는 개체(예 Async.StartImmediate : 또는 Async.RunSynchronously)로 만듭니다. 사용하는 let! 코드 줄은 계산을 시작하고 비동기 대기를 수행합니다. 스레드는 결과를 사용할 수 있게 될 때까지 일시 중단되며, 이때 실행이 계속됩니다.

// let just stores the result as an asynchronous operation.
let (result1 : Async<byte[]>) = stream.AsyncRead(bufferSize)
// let! completes the asynchronous operation and returns the data.
let! (result2 : byte[])  = stream.AsyncRead(bufferSize)

let! 는 F# 비동기 계산을 직접 기다리는 데만 사용할 수 있습니다 Async<T> . 다른 종류의 비동기 작업을 간접적으로 기다릴 수 있습니다.

  • .NET 작업 및 제네릭Task이 아닌 작업 Task<TResult> 과 결합Async.AwaitTask
  • .NET 값 작업 ValueTask<TResult> 및 제네릭 ValueTask이 아닌 작업과 .AsTask() 결합하여 Async.AwaitTask
  • 와 결합하여 task { return! expr } |> Async.AwaitTaskF# RFC FS-1097지정된 "GetAwaiter" 패턴을 따르는 모든 개체입니다.

제어 흐름

비동기 식에는 컨트롤 흐름 구문(예: for .. in .. do, while .. do, try .. with .., try .. finally ..if .. then .. elseif .. then ..)이 포함될 수 있습니다. 따라서 동기적으로 실행되는 처리기 및 finally 처리기를 제외하고 with 추가 비동기 구문을 포함할 수 있습니다.

F# 비동기 식은 비동 try .. finally ..기 식을 지원하지 않습니다. 이 경우 작업 식을 사용할 수 있습니다.

useuse! 바인딩

비동기 식 use 내에서 바인딩은 형식 IDisposable의 값에 바인딩할 수 있습니다. 후자의 경우 삭제 클린up 작업이 비동기적으로 실행됩니다.

또한 let!비동기 바인딩을 수행하는 데 사용할 use! 수 있습니다. 사이의 let! 차이와 use! 은(는) 사이의 let 차이와 use같습니다. 의 경우 use!개체는 현재 범위의 닫기에서 삭제됩니다. F# use! 의 현재 릴리스에서는 값이 null use 로 초기화되는 것을 허용하지 않습니다.

비동기 기본 형식

단일 비동기 작업을 수행하고 결과를 반환하는 메서드를 비동기 기본 형식이라고 하며, 이러한 메서드는 사용할 수 let!있도록 특별히 설계되었습니다. F# 코어 라이브러리에는 여러 비동기 기본 형식이 정의되어 있습니다. 웹 애플리케이션에 대한 두 가지 메서드는 모듈 FSharp.Control.WebExtensionsWebRequest.AsyncGetResponseWebClient.AsyncDownloadString에서 정의됩니다. 두 기본 형식 모두 URL이 지정된 웹 페이지에서 데이터를 다운로드합니다. AsyncGetResponse 는 개체를 System.Net.WebResponse 생성하고 AsyncDownloadString 웹 페이지의 HTML을 나타내는 문자열을 생성합니다.

비동기 I/O 작업에 대한 몇 가지 기본 형식이 모듈에 FSharp.Control.CommonExtensions 포함됩니다. 클래스의 이러한 확장 메서드는 System.IO.Stream 다음과 같습니다Stream.AsyncWriteStream.AsyncRead.

본문이 비동기 식인 함수 또는 메서드를 정의하여 고유한 비동기 기본 형식을 작성할 수도 있습니다.

F# 비동기 프로그래밍 모델을 사용하여 다른 비동기 모델을 위해 설계된 .NET Framework에서 비동기 메서드를 사용하려면 F# Async 개체를 반환하는 함수를 만듭니다. F# 라이브러리에는 이 작업을 쉽게 수행할 수 있는 함수가 있습니다.

비동기 식을 사용하는 한 가지 예가 여기에 포함되어 있습니다. 설명서에는 비동기 클래스의 메서드에 대한 많은 다른 항목이 있습니다.

이 예제에서는 비동기 식을 사용하여 코드를 병렬로 실행하는 방법을 보여 줍니다.

다음 코드 예제에서 함수 fetchAsync 는 웹 요청에서 반환된 HTML 텍스트를 가져옵니다. 함수에는 fetchAsync 비동기 코드 블록이 포함되어 있습니다. 비동기 기본 형식의 결과에 바인딩이 만들어지면 이 경우 AsyncDownloadStringlet! 대신 사용됩니다let.

함수 Async.RunSynchronously 를 사용하여 비동기 작업을 실행하고 결과를 기다립니다. 예를 들어 함수와 함께 함수를 사용하여 Async.Parallel 여러 비동기 작업을 병렬로 Async.RunSynchronously 실행할 수 있습니다. 함수는 Async.Parallel 개체 목록을 Async 사용하고, 각 Async 작업 개체가 병렬로 실행되도록 코드를 설정하고, 병렬 계산을 Async 나타내는 개체를 반환합니다. 단일 작업과 마찬가지로 실행을 시작하도록 호출 Async.RunSynchronously 합니다.

이 함수는 runAll 세 개의 비동기 식을 병렬로 시작하고 모두 완료될 때까지 기다립니다.

open System.Net
open Microsoft.FSharp.Control.WebExtensions

let urlList = [ "Microsoft.com", "http://www.microsoft.com/"
                "MSDN", "http://msdn.microsoft.com/"
                "Bing", "http://www.bing.com"
              ]

let fetchAsync(name, url:string) =
    async {
        try
            let uri = new System.Uri(url)
            let webClient = new WebClient()
            let! html = webClient.AsyncDownloadString(uri)
            printfn "Read %d characters for %s" html.Length name
        with
            | ex -> printfn "%s" (ex.Message);
    }

let runAll() =
    urlList
    |> Seq.map fetchAsync
    |> Async.Parallel
    |> Async.RunSynchronously
    |> ignore

runAll()

참고 항목