非同期ワークフローAsynchronous workflows

この記事では、計算を非同期的に実行する F # のサポートについて説明します。つまり、他の作業の実行をブロックすることはありません。This article describes support in F# for performing computations asynchronously, that is, without blocking execution of other work. たとえば、非同期計算を使用して、アプリケーションが他の作業を実行するときにユーザーに応答し続ける Ui を持つアプリケーションを作成できます。For example, asynchronous computations can be used to write applications that have UIs that remain responsive to users as the application performs other work.

構文Syntax

async { expression }

解説Remarks

前の構文では、によって表される計算 expression が非同期的に実行されるように設定されています。つまり、非同期スリープ操作、i/o、およびその他の非同期操作が実行されるときに、現在の計算スレッドをブロックしません。In the previous syntax, the computation represented by expression is set up to run asynchronously, that is, without blocking the current computation thread when asynchronous sleep operations, I/O, and other asynchronous operations are performed. 非同期計算は、多くの場合、現在のスレッドで実行を継続しながらバックグラウンドスレッドで開始されます。Asynchronous computations are often started on a background thread while execution continues on the current thread. 式の型はです Async<'T> 。ここで、 'T は、 return キーワードが使用されている場合に、式によって返される型です。The type of the expression is Async<'T>, where 'T is the type returned by the expression when the return keyword is used. このような式のコードは、 非同期ブロックまたは非同期 ブロックと呼ばれます。The code in such an expression is referred to as an asynchronous block, or async block.

非同期プログラミングにはさまざまな方法があり、クラスには Async いくつかのシナリオをサポートするメソッドが用意されています。There are a variety of ways of programming asynchronously, and the Async class provides methods that support several scenarios. 一般的な方法では、 Async 非同期的に実行する計算または計算を表すオブジェクトを作成し、トリガー関数のいずれかを使用して、これらの計算を開始します。The general approach is to create Async objects that represent the computation or computations that you want to run asynchronously, and then start these computations by using one of the triggering functions. さまざまなトリガー関数は、非同期計算を実行するさまざまな方法を提供します。どちらを使用するかは、現在のスレッド、バックグラウンドスレッド、.NET Framework タスクオブジェクトを使用するかどうか、および計算が終了したときに実行する必要のある継続関数があるかどうかによって異なります。The various triggering functions provide different ways of running asynchronous computations, and which one you use depends on whether you want to use the current thread, a background thread, or a .NET Framework task object, and whether there are continuation functions that should run when the computation finishes. たとえば、現在のスレッドで非同期計算を開始するには、を使用し Async.StartImmediate ます。For example, to start an asynchronous computation on the current thread, you can use Async.StartImmediate. UI スレッドから非同期計算を開始する場合は、キーストロークやマウスアクティビティなどのユーザー操作を処理するメインイベントループをブロックしないため、アプリケーションの応答性が維持されます。When you start an asynchronous computation from the UI thread, you do not block the main event loop that processes user actions such as keystrokes and mouse activity, so your application remains responsive.

Let を使用した非同期バインドAsynchronous Binding by Using let!

非同期ワークフローでは、一部の式と操作は同期的であり、一部の式と操作は、非同期的に結果を返すように設計された、より長い計算です。In an asynchronous workflow, some expressions and operations are synchronous, and some are longer computations that are designed to return a result asynchronously. 通常のバインディングではなく、メソッドを非同期的に呼び出す場合は、を let 使用し let! ます。When you call a method asynchronously, instead of an ordinary let binding, you use let!. の効果は、 let! 計算の実行中に、他の計算やスレッドで実行を継続できるようにすることです。The effect of let! is to enable execution to continue on other computations or threads as the computation is being performed. バインディングの右側から制御が戻った後、 let! 非同期ワークフローの残りの部分は実行を再開します。After the right side of the let! binding returns, the rest of the asynchronous workflow resumes execution.

次のコードは、との違いを示して let let! います。The following code shows the difference between let and let!. を使用するコード行で let は、またはなどを使用して後で実行できるオブジェクトとして非同期計算を作成し Async.StartImmediate Async.RunSynchronously ます。The line of code that uses let just creates an asynchronous computation as an object that you can run later by using, for example, Async.StartImmediate or Async.RunSynchronously. を使用するコード行によって計算が開始され、その let! 後、結果が使用可能になるまでスレッドが中断されます。The line of code that uses let! starts the computation, and then the thread is suspended until the result is available, at which point execution continues.

// 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! 、を使用して非同期バインディングを実行することもでき use! ます。In addition to let!, you can use use! to perform asynchronous bindings. との違い let! は、との違い use! と同じです let useThe difference between let! and use! is the same as the difference between let and use. の場合 use! 、オブジェクトは現在のスコープの終了時に破棄されます。For use!, the object is disposed of at the close of the current scope. 現在のリリースの F # 言語では、がの場合でも、値を null に初期化することはできないことに注意して use! use ください。Note that in the current release of the F# language, use! does not allow a value to be initialized to null, even though use does.

非同期プリミティブAsynchronous Primitives

1つの非同期タスクを実行し、その結果を返すメソッドは、 非同期プリミティブと呼ばれ、専用に設計されてい let! ます。A method that performs a single asynchronous task and returns the result is called an asynchronous primitive, and these are designed specifically for use with let!. いくつかの非同期プリミティブは、F # コアライブラリで定義されています。Several asynchronous primitives are defined in the F# core library. このような Web アプリケーションの2つのメソッドは、モジュールで定義されて FSharp.Control.WebExtensions WebRequest.AsyncGetResponse WebClient.AsyncDownloadString います。Two such methods for Web applications are defined in the module FSharp.Control.WebExtensions: WebRequest.AsyncGetResponse and WebClient.AsyncDownloadString. どちらのプリミティブも、URL を指定して Web ページからデータをダウンロードします。Both primitives download data from a Web page, given a URL. AsyncGetResponse オブジェクトを生成 System.Net.WebResponse し、 AsyncDownloadString Web ページの HTML を表す文字列を生成します。AsyncGetResponse produces a System.Net.WebResponse object, and AsyncDownloadString produces a string that represents the HTML for a Web page.

非同期 i/o 操作のためのいくつかのプリミティブは、モジュールに含まれてい FSharp.Control.CommonExtensions ます。Several primitives for asynchronous I/O operations are included in the FSharp.Control.CommonExtensions module. クラスの拡張メソッド System.IO.StreamStream.AsyncRead 、と Stream.AsyncWrite です。These extension methods of the System.IO.Stream class are Stream.AsyncRead and Stream.AsyncWrite.

また、完全な本文が非同期ブロックで囲まれた関数を定義することで、独自の非同期プリミティブを作成することもできます。You can also write your own asynchronous primitives by defining a function whose complete body is enclosed in an async block.

F # の非同期プログラミングモデルを使用して他の非同期モデル用にデザインされた .NET Framework で非同期メソッドを使用するには、F # オブジェクトを返す関数を作成し Async ます。To use asynchronous methods in the .NET Framework that are designed for other asynchronous models with the F# asynchronous programming model, you create a function that returns an F# Async object. F # ライブラリには、これを簡単に実行できる関数が用意されています。The F# library has functions that make this easy to do.

非同期ワークフローの使用例を次に示します。 非同期クラスのメソッドに関するドキュメントには、他にも多くのものがあります。One example of using asynchronous workflows is included here; there are many others in the documentation for the methods of the Async class.

この例では、非同期ワークフローを使用して並列で計算を実行する方法を示します。This example shows how to use asynchronous workflows to perform computations in parallel.

次のコード例では、関数は fetchAsync Web 要求から返された HTML テキストを取得します。In the following code example, a function fetchAsync gets the HTML text returned from a Web request. 関数には、 fetchAsync 非同期のコードブロックが含まれています。The fetchAsync function contains an asynchronous block of code. 非同期プリミティブの結果にバインドが行われた場合、この場合 AsyncDownloadString let! はの代わりにが使用され let ます。When a binding is made to the result of an asynchronous primitive, in this case AsyncDownloadString, let! is used instead of let.

関数を使用し Async.RunSynchronously て非同期操作を実行し、その結果を待機します。You use the function Async.RunSynchronously to execute an asynchronous operation and wait for its result. 例として、関数を関数と共に使用することで、複数の非同期操作を並列で実行でき Async.Parallel Async.RunSynchronously ます。As an example, you can execute multiple asynchronous operations in parallel by using the Async.Parallel function together with the Async.RunSynchronously function. 関数は、 Async.Parallel オブジェクトの一覧を取得し Async 、各タスクオブジェクトのコードを Async 並列で実行するように設定し、 Async 並列計算を表すオブジェクトを返します。The Async.Parallel function takes a list of the Async objects, sets up the code for each Async task object to run in parallel, and returns an Async object that represents the parallel computation. 1回の操作と同じように、を呼び出して Async.RunSynchronously 実行を開始します。Just as for a single operation, you call Async.RunSynchronously to start the execution.

関数は、 runAll 3 つの非同期ワークフローを並列で起動し、すべてが完了するまで待機します。The runAll function launches three asynchronous workflows in parallel and waits until they have all completed.

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()

関連項目See also