Async-Programmierung in F-#Async programming in F#

Bei der asynchronen Programmierung handelt es sich um einen Mechanismus, der aus unterschiedlichen Gründen für moderne Anwendungen unverzichtbar ist.Asynchronous programming is a mechanism that is essential to modern applications for diverse reasons. Es gibt zwei Haupt Anwendungsfälle, auf die die meisten Entwickler stoßen werden:There are two primary use cases that most developers will encounter:

  • Präsentieren eines Server Prozesses, der eine beträchtliche Anzahl gleichzeitiger eingehender Anforderungen verarbeiten kann, während gleichzeitig die Systemressourcen minimiert werden, die während der Verarbeitung der Anforderung belegt werdenPresenting a server process that can service a significant number of concurrent incoming requests, while minimizing the system resources occupied while request processing awaits inputs from systems or services external to that process
  • Beibehalten einer reaktionsfähigen Benutzeroberfläche oder eines Haupt Threads, während gleichzeitig Hintergrund arbeitenMaintaining a responsive UI or main thread while concurrently progressing background work

Obwohl Hintergrundarbeit häufig die Verwendung mehrerer Threads umfasst, ist es wichtig, die Konzepte von Asynchronität und Multithreading separat zu betrachten.Although background work often does involve the utilization of multiple threads, it's important to consider the concepts of asynchrony and multi-threading separately. Tatsächlich handelt es sich dabei um getrennte Aspekte, und eine davon impliziert nicht das andere.In fact, they are separate concerns, and one does not imply the other. Dies wird in diesem Artikel ausführlicher beschrieben.What follows in this article describes this in more detail.

Asynchronität definiertAsynchrony defined

Der vorherige Punkt, dass Asynchronität unabhängig von der Verwendung mehrerer Threads ist, sollte etwas weiter erläutert werden.The previous point - that asynchrony is independent of the utilization of multiple threads - is worth explaining a bit further. Es gibt drei Konzepte, die manchmal in Beziehung zueinander stehen, aber streng voneinander unabhängig sind:There are three concepts that are sometimes related, but strictly independent of one another:

  • Concurrency Wenn mehrere Berechnungen in überlappenden Zeiträumen ausgeführt werden.Concurrency; when multiple computations execute in overlapping time periods.
  • Parallelität Wenn mehrere Berechnungen oder mehrere Teile einer einzelnen Berechnung gleichzeitig ausgeführt werden.Parallelism; when multiple computations or several parts of a single computation run at exactly the same time.
  • Asynchronie Wenn eine oder mehrere Berechnungen getrennt vom Hauptprogramm Ablauf ausgeführt werden können.Asynchrony; when one or more computations can execute separately from the main program flow.

Alle drei sind orthogonale Konzepte, können aber problemlos zusammengeführt werden, insbesondere, wenn Sie zusammen verwendet werden.All three are orthogonal concepts, but can be easily conflated, especially when they are used together. Beispielsweise müssen Sie möglicherweise mehrere asynchrone Berechnungen parallel ausführen.For example, you may need to execute multiple asynchronous computations in parallel. Dies bedeutet nicht, dass Parallelität oder Asynchronität einander impliziert.This does not mean that parallelism or asynchrony imply one another.

Wenn Sie die Etymologie des Worts "asynchron" in Erwägung gezogen haben, sind zwei Teile beteiligt:If you consider the etymology of the word "asynchronous", there are two pieces involved:

  • "a", d. h. "Not"."a", meaning "not".
  • "synchron", d. h. gleichzeitig."synchronous", meaning "at the same time".

Wenn Sie diese beiden Begriffe zusammenfassen, sehen Sie, dass "asynchron" bedeutet "nicht gleichzeitig".When you put these two terms together, you'll see that "asynchronous" means "not at the same time". Das ist alles!That's it! In dieser Definition gibt es keine Implikation oder Parallelität.There is no implication of concurrency or parallelism in this definition. Dies gilt auch in der Praxis.This is also true in practice.

In praktischer Hinsicht werden asynchrone Berechnungen in F# so geplant, dass Sie unabhängig vom Hauptprogramm Fluss ausgeführt werden.In practical terms, asynchronous computations in F# are scheduled to execute independently of the main program flow. Dies impliziert nicht Parallelität oder Parallelität und impliziert nicht, dass eine Berechnung immer im Hintergrund erfolgt.This doesn't imply concurrency or parallelism, nor does it imply that a computation always happens in the background. Asynchrone Berechnungen können sogar synchron ausgeführt werden, abhängig von der Art der Berechnung und der Umgebung, in der die Berechnung ausgeführt wird.In fact, asynchronous computations can even execute synchronously, depending on the nature of the computation and the environment the computation is executing in.

Das wichtigste, was Sie tun sollten, ist, dass asynchrone Berechnungen unabhängig vom Hauptprogramm Fluss sind.The main takeaway you should have is that asynchronous computations are independent of the main program flow. Obwohl es nur wenige Garantien gibt, wann oder wie eine asynchrone Berechnung ausgeführt wird, gibt es einige Ansätze zum orchestrieren und planen.Although there are few guarantees about when or how an asynchronous computation executes, there are some approaches to orchestrating and scheduling them. Im restlichen Teil dieses Artikels werden die Kernkonzepte F# für asynchroniität und die Verwendung der in F#integrierten Typen, Funktionen und Ausdrücke erläutert.The rest of this article explores core concepts for F# asynchrony and how to use the types, functions, and expressions built into F#.

Wichtige KonzepteCore concepts

In F#wird die asynchrone Programmierung auf drei Kernkonzepte zentriert:In F#, asynchronous programming is centered around three core concepts:

  • Der Async<'T> Typ, der eine Zusammensetz Bare asynchrone Berechnung darstellt.The Async<'T> type, which represents a composable asynchronous computation.
  • Die Async Modulfunktionen, mit denen Sie asynchrone Arbeit planen, asynchrone Berechnungen verfassen und asynchrone Ergebnisse transformieren können.The Async module functions, which let you schedule asynchronous work, compose asynchronous computations, and transform asynchronous results.
  • Der async { } Berechnungs Ausdruck, der eine bequeme Syntax zum entwickeln und Steuern von asynchronen Berechnungen bereitstellt.The async { } computation expression, which provides a convenient syntax for building and controlling asynchronous computations.

Diese drei Konzepte finden Sie im folgenden Beispiel:You can see these three concepts in the following example:

open System
open System.IO

let printTotalFileBytes path =
    async {
        let! bytes = File.ReadAllBytesAsync(path) |> Async.AwaitTask
        let fileName = Path.GetFileName(path)
        printfn "File %s has %d bytes" fileName bytes.Length
    }

[<EntryPoint>]
let main argv =
    printTotalFileBytes "path-to-file.txt"
    |> Async.RunSynchronously

    Console.Read() |> ignore
    0

Im Beispiel ist die printTotalFileBytes-Funktion vom Typ string -> Async<unit>.In the example, the printTotalFileBytes function is of type string -> Async<unit>. Durch den Aufruf der-Funktion wird die asynchrone Berechnung nicht ausgeführt.Calling the function does not actually execute the asynchronous computation. Stattdessen wird ein Async<unit> zurückgegeben, das als Spezifikation der Arbeit fungiert, die asynchron ausgeführt werden soll.Instead, it returns an Async<unit> that acts as a specification of the work that is to execute asynchronously. Es wird Async.AwaitTask im Textkörper aufgerufen, der das Ergebnis des ReadAllBytesAsync in einen entsprechenden Typ konvertiert.It calls Async.AwaitTask in its body, which converts the result of ReadAllBytesAsync to an appropriate type.

Eine weitere wichtige Zeile ist der aufzurufende Async.RunSynchronously.Another important line is the call to Async.RunSynchronously. Dies ist eines der asynchronen Modul Startfunktionen, die Sie aufrufen müssen, wenn Sie eine F# asynchrone Berechnung tatsächlich ausführen möchten.This is one of the Async module starting functions that you'll need to call if you want to actually execute an F# asynchronous computation.

Dies ist ein grundlegender Unterschied C#zum/Visual Basic-Stil der async Programmierung.This is a fundamental difference with the C#/Visual Basic style of async programming. In F#können sich asynchrone Berechnungen als kalte Aufgabenvorstellen.In F#, asynchronous computations can be thought of as Cold tasks. Sie müssen explizit gestartet werden, damit Sie tatsächlich ausgeführt werden.They must be explicitly started to actually execute. Dies hat einige Vorteile, da es Ihnen ermöglicht, asynchrone Aufgaben viel einfacher zu kombinieren und zu sequenzieren als in C# oder Visual Basic.This has some advantages, as it allows you to combine and sequence asynchronous work much more easily than in C# or Visual Basic.

Kombinieren von asynchronen BerechnungenCombine asynchronous computations

Im folgenden finden Sie ein Beispiel, das auf dem vorherigen basiert, indem Berechnungen kombiniert werden:Here is an example that builds upon the previous one by combining computations:

open System
open System.IO

let printTotalFileBytes path =
    async {
        let! bytes = File.ReadAllBytesAsync(path) |> Async.AwaitTask
        let fileName = Path.GetFileName(path)
        printfn "File %s has %d bytes" fileName bytes.Length
    }

[<EntryPoint>]
let main argv =
    argv
    |> Array.map printTotalFileBytes
    |> Async.Parallel
    |> Async.Ignore
    |> Async.RunSynchronously

    0

Wie Sie sehen können, hat die main-Funktion ziemlich viele weitere Aufrufe.As you can see, the main function has quite a few more calls made. Konzeptionell werden folgende Aktionen durchführt:Conceptually, it does the following:

  1. Transformieren Sie die Befehlszeilenargumente in Async<unit> Berechnungen mit Array.map.Transform the command-line arguments into Async<unit> computations with Array.map.
  2. Erstellen Sie eine Async<'T[]>, die die printTotalFileBytes Berechnungen parallel bei der Ausführung plant und ausführt.Create an Async<'T[]> that schedules and runs the printTotalFileBytes computations in parallel when it runs.
  3. Erstellen Sie einen Async<unit>, der die parallele Berechnung ausführt und das Ergebnis ignoriert.Create an Async<unit> that will run the parallel computation and ignore its result.
  4. Führen Sie die Letzte Berechnung mit Async.RunSynchronously, und blockieren Sie Sie, bis Sie abgeschlossen ist.Explicitly run the last computation with Async.RunSynchronously and block until it is completes.

Wenn das Programm ausgeführt wird, werden printTotalFileBytes für jedes Befehlszeilenargument parallel ausgeführt.When this program runs, printTotalFileBytes runs in parallel for each command-line argument. Da asynchrone Berechnungen unabhängig vom Programmablauf ausgeführt werden, gibt es keine Reihenfolge, in der Sie Ihre Informationen ausdrucken und die Ausführung abschließen.Because asynchronous computations execute independently of program flow, there is no order in which they print their information and finish executing. Die Berechnungen werden parallel geplant, aber ihre Ausführungsreihenfolge ist nicht sichergestellt.The computations will be scheduled in parallel, but their order of execution is not guaranteed.

Asynchrone Berechnungen SequenzierenSequence asynchronous computations

Da Async<'T> eine Spezifikation der Arbeit anstelle einer bereits ausgeführten Aufgabe ist, können Sie kompliziertere Transformationen problemlos ausführen.Because Async<'T> is a specification of work rather than an already-running task, you can perform more intricate transformations easily. Im folgenden Beispiel wird ein Satz asynchroner Berechnungen sequenziert, sodass Sie nacheinander nacheinander ausgeführt werden.Here is an example that sequences a set of Async computations so they execute one after another.

let printTotalFileBytes path =
    async {
        let! bytes = File.ReadAllBytesAsync(path) |> Async.AwaitTask
        let fileName = Path.GetFileName(path)
        printfn "File %s has %d bytes" fileName bytes.Length
    }

[<EntryPoint>]
let main argv =
    argv
    |> Array.map printTotalFileBytes
    |> Async.Sequential
    |> Async.Ignore
    |> Async.RunSynchronously
    |> ignore

Dadurch wird geplant, printTotalFileBytes in der Reihenfolge der Elemente argv auszuführen, anstatt sie parallel zu planen.This will schedule printTotalFileBytes to execute in the order of the elements of argv rather than scheduling them in parallel. Da das nächste Element erst geplant wird, nachdem die Ausführung der letzten Berechnung abgeschlossen ist, werden die Berechnungen so sequenziert, dass Sie sich nicht überlappen.Because the next item will not be scheduled until after the last computation has finished executing, the computations are sequenced such that there is no overlap in their execution.

Wichtige Async-ModulfunktionenImportant Async module functions

Wenn Sie asynchronen Code in F# schreiben, interagieren Sie in der Regel mit einem Framework, das die Planung von Berechnungen für Sie behandelt.When you write async code in F# you'll usually interact with a framework that handles scheduling of computations for you. Dies ist jedoch nicht immer der Fall. es ist daher sinnvoll, die verschiedenen Startfunktionen zu erlernen, um asynchrone Aufgaben zu planen.However, this is not always the case, so it is good to learn the various starting functions to schedule asynchronous work.

Da F# es sich bei asynchronen Berechnungen um eine Spezifikation der Arbeit und nicht um eine Darstellung der bereits ausgeführten Arbeit handelt, müssen Sie explizit mit einer Start Funktion gestartet werden.Because F# asynchronous computations are a specification of work rather than a representation of work that is already executing, they must be explicitly started with a starting function. Es gibt viele Async-Startfunktionen , die in unterschiedlichen Kontexten hilfreich sind.There are many Async starting functions that are helpful in different contexts. Im folgenden Abschnitt werden einige der gängigeren Startfunktionen beschrieben.The following section describes some of the more common starting functions.

Async. startchildAsync.StartChild

Startet eine untergeordnete Berechnung in einer asynchronen Berechnung.Starts a child computation within an asynchronous computation. Dies ermöglicht die gleichzeitige Ausführung mehrerer asynchroner Berechnungen.This allows multiple asynchronous computations to be executed concurrently. Die untergeordnete Berechnung gibt ein Abbruch Token mit der übergeordneten Berechnung frei.The child computation shares a cancellation token with the parent computation. Wenn die übergeordnete Berechnung abgebrochen wird, wird die untergeordnete Berechnung ebenfalls abgebrochen.If the parent computation is canceled, the child computation is also canceled.

Signatur:Signature:

computation: Async<'T> - timeout: ?int -> Async<Async<'T>>

Verwendungszwecke:When to use:

  • Wenn Sie mehrere asynchrone Berechnungen gleichzeitig statt einzeln ausführen möchten, diese jedoch nicht parallel geplant sind.When you want to execute multiple asynchronous computations concurrently rather than one at a time, but not have them scheduled in parallel.
  • , Wenn die Lebensdauer einer untergeordneten Berechnung an die einer übergeordneten Berechnung gebunden werden soll.When you wish to tie the lifetime of a child computation to that of a parent computation.

Zu überwachende Elemente:What to watch out for:

  • Das Starten mehrerer Berechnungen mit Async.StartChild ist nicht dasselbe wie das parallele planen.Starting multiple computations with Async.StartChild isn't the same as scheduling them in parallel. Wenn Sie Berechnungen parallel planen möchten, verwenden Sie Async.Parallel.If you wish to schedule computations in parallel, use Async.Parallel.
  • Beim Abbrechen einer übergeordneten Berechnung werden alle untergeordneten Berechnungen abgebrochen, die gestartet wurden.Canceling a parent computation will trigger cancellation of all child computations it started.

Async. startimvermittlerAsync.StartImmediate

Führt eine asynchrone Berechnung aus, die sofort im aktuellen Betriebssystemthread beginnt.Runs an asynchronous computation, starting immediately on the current operating system thread. Dies ist hilfreich, wenn Sie während der Berechnung etwas auf dem aufrufenden Thread aktualisieren müssen.This is helpful if you need to update something on the calling thread during the computation. Wenn eine asynchrone Berechnung z. b. eine Benutzeroberfläche aktualisieren muss (z. b. das Aktualisieren einer Statusanzeige), sollten Async.StartImmediate verwendet werden.For example, if an asynchronous computation must update a UI (such as updating a progress bar), then Async.StartImmediate should be used.

Signatur:Signature:

computation: Async<unit> - cancellationToken: ?CancellationToken -> unit

Verwendungszwecke:When to use:

  • Wenn Sie etwas auf dem aufrufenden Thread in der Mitte einer asynchronen Berechnung aktualisieren müssen.When you need to update something on the calling thread in the middle of an asynchronous computation.

Zu überwachende Elemente:What to watch out for:

  • Der Code in der asynchronen Berechnung wird auf dem Thread ausgeführt, für den eine geplante Berechnung durchgeführt wird.Code in the asynchronous computation will run on whatever thread one happens to be scheduled on. Dies kann problematisch sein, wenn dieser Thread in gewisser Weise sensibel ist, z. b. in einem UI-Thread.This can be problematic if that thread is in some way sensitive, such as a UI thread. In solchen Fällen ist die Verwendung von Async.StartImmediate wahrscheinlich ungeeignet.In such cases, Async.StartImmediate is likely inappropriate to use.

Async. startastaskAsync.StartAsTask

Führt eine Berechnung im Threadpool aus.Executes a computation in the thread pool. Gibt einen Task<TResult> zurück, der im entsprechenden Zustand abgeschlossen wird, sobald die Berechnung beendet wird (das Ergebnis erzeugt, eine Ausnahme auslöst oder abgebrochen wird).Returns a Task<TResult> that will be completed on the corresponding state once the computation terminates (produces the result, throws exception, or gets canceled). Wenn kein Abbruch Token bereitgestellt wird, wird das Standard Abbruch Token verwendet.If no cancellation token is provided, then the default cancellation token is used.

Signatur:Signature:

computation: Async<'T> - taskCreationOptions: ?TaskCreationOptions - cancellationToken: ?CancellationToken -> Task<'T>

Verwendungszwecke:When to use:

  • Wenn eine .NET-API aufgerufen werden muss, die erwartet, dass eine Task<TResult> das Ergebnis einer asynchronen Berechnung darstellt.When you need to call into a .NET API that expects a Task<TResult> to represent the result of an asynchronous computation.

Zu überwachende Elemente:What to watch out for:

  • Dieser Befehl weist ein zusätzliches Task-Objekt zu, das den mehr Aufwand erhöhen kann, wenn es häufig verwendet wird.This call will allocate an additional Task object, which can increase overhead if it is used often.

Async. parallelAsync.Parallel

Plant die parallele Ausführung einer Sequenz von asynchronen Berechnungen.Schedules a sequence of asynchronous computations to be executed in parallel. Der Grad an Parallelität kann optional optimiert/gedrosselt werden, indem der maxDegreesOfParallelism-Parameter angegeben wird.The degree of parallelism can be optionally tuned/throttled by specifying the maxDegreesOfParallelism parameter.

Signatur:Signature:

computations: seq<Async<'T>> - ?maxDegreesOfParallelism: int -> Async<'T[]>

Verwendung:When to use it:

  • Wenn Sie einen Satz von Berechnungen gleichzeitig ausführen müssen und nicht von der Ausführungsreihenfolge abhängig sind.If you need to run a set of computations at the same time and have no reliance on their order of execution.
  • Wenn Sie keine Ergebnisse von Berechnungen benötigen, die parallel geplant sind, bis alle abgeschlossen sind.If you don't require results from computations scheduled in parallel until they have all completed.

Zu überwachende Elemente:What to watch out for:

  • Sie können nur auf das resultierende Array von Werten zugreifen, nachdem alle Berechnungen abgeschlossen wurden.You can only access the resulting array of values once all computations have finished.
  • Berechnungen werden ausgeführt, Sie werden jedoch am Ende geplant.Computations will be run however they end up getting scheduled. Dies bedeutet, dass Sie sich nicht auf die Reihenfolge ihrer Ausführung verlassen können.This means you cannot rely on their order of their execution.

Async. SequentialAsync.Sequential

Plant eine Sequenz von asynchronen Berechnungen, die in der Reihenfolge ausgeführt werden, in der Sie übermittelt werden.Schedules a sequence of asynchronous computations to be executed in the order that they are passed. Die erste Berechnung wird ausgeführt, dann die nächste, usw.The first computation will be executed, then the next, and so on. Keine Berechnungen werden parallel ausgeführt.No computations will be executed in parallel.

Signatur:Signature:

computations: seq<Async<'T>> -> Async<'T[]>

Verwendung:When to use it:

  • Wenn Sie mehrere Berechnungen in der richtigen Reihenfolge ausführen müssen.If you need to execute multiple computations in order.

Zu überwachende Elemente:What to watch out for:

  • Sie können nur auf das resultierende Array von Werten zugreifen, nachdem alle Berechnungen abgeschlossen wurden.You can only access the resulting array of values once all computations have finished.
  • Berechnungen werden in der Reihenfolge ausgeführt, in der Sie an diese Funktion weitergeleitet werden. Dies kann bedeuten, dass mehr Zeit verstrichen ist, bevor die Ergebnisse zurückgegeben werden.Computations will be run in the order that they are passed to this function, which can mean that more time will elapse before the results are returned.

Async. awaittaskAsync.AwaitTask

Gibt eine asynchrone Berechnung zurück, die auf den Abschluss der angegebenen Task<TResult> wartet und das Ergebnis als Async<'T> zurückgibt.Returns an asynchronous computation that waits for the given Task<TResult> to complete and returns its result as an Async<'T>

Signatur:Signature:

task: Task<'T>  -> Async<'T>

Verwendungszwecke:When to use:

  • Wenn Sie eine .NET-API verwenden, die eine Task<TResult> in einer F# asynchronen Berechnung zurückgibt.When you are consuming a .NET API that returns a Task<TResult> within an F# asynchronous computation.

Zu überwachende Elemente:What to watch out for:

  • Ausnahmen werden AggregateException nach der Konvention der Task Parallel Library umschließt. Dies unterscheidet sich von der allgemeinen F# Verwendung von Ausnahmen durch Async.Exceptions are wrapped in AggregateException following the convention of the Task Parallel Library, and this is different from how F# async generally surfaces exceptions.

Async. catchAsync.Catch

Erstellt eine asynchrone Berechnung, die eine angegebene Async<'T>ausführt und eine Async<Choice<'T, exn>>zurückgibt.Creates an asynchronous computation that executes a given Async<'T>, returning an Async<Choice<'T, exn>>. Wenn die angegebene Async<'T> erfolgreich abgeschlossen wird, wird ein Choice1Of2 mit dem resultierenden Wert zurückgegeben.If the given Async<'T> completes successfully, then a Choice1Of2 is returned with the resultant value. Wenn eine Ausnahme ausgelöst wird, bevor Sie abgeschlossen wird, wird eine Choice2of2 mit der ausgelösten Ausnahme zurückgegeben.If an exception is thrown before it completes, then a Choice2of2 is returned with the raised exception. Wenn Sie für eine asynchrone Berechnung verwendet wird, die selbst aus vielen Berechnungen besteht, und eine dieser Berechnungen eine Ausnahme auslöst, wird die umfassende Berechnung vollständig beendet.If it is used on an asynchronous computation that is itself composed of many computations, and one of those computations throws an exception, the encompassing computation will be stopped entirely.

Signatur:Signature:

computation: Async<'T> -> Async<Choice<'T, exn>>

Verwendungszwecke:When to use:

  • Wenn Sie asynchrone Aufgaben ausführen, die möglicherweise mit einer Ausnahme fehlschlagen, und Sie diese Ausnahme im Aufrufer behandeln möchten.When you are performing asynchronous work that may fail with an exception and you want to handle that exception in the caller.

Zu überwachende Elemente:What to watch out for:

  • Bei kombinierten oder sequenzierten asynchronen Berechnungen wird die umfassende Berechnung vollständig beendet, wenn eine ihrer "internen" Berechnungen eine Ausnahme auslöst.When using combined or sequenced asynchronous computations, the encompassing computation will fully stop if one of its "internal" computations throws an exception.

Async. IgnoreAsync.Ignore

Erstellt eine asynchrone Berechnung, die die angegebene Berechnung ausführt und das Ergebnis ignoriert.Creates an asynchronous computation that runs the given computation and ignores its result.

Signatur:Signature:

computation: Async<'T> -> Async<unit>

Verwendungszwecke:When to use:

  • Wenn eine asynchrone Berechnung vorhanden ist, deren Ergebnis nicht benötigt wird.When you have an asynchronous computation whose result is not needed. Dies entspricht dem ignore-Code für nicht asynchronen Code.This is analogous to the ignore code for non-asynchronous code.

Zu überwachende Elemente:What to watch out for:

  • Wenn Sie diese verwenden müssen, da Sie Async.Start oder eine andere Funktion verwenden möchten, die Async<unit>erfordert, sollten Sie Bedenken, ob das Verwerfen des Ergebnisses in Ordnung ist.If you must use this because you wish to use Async.Start or another function that requires Async<unit>, consider if discarding the result is okay to do. Das Verwerfen von Ergebnissen, die nur an eine Typsignatur angepasst werden, sollte in der Regel nicht erfolgen.Discarding results just to fit a type signature should not generally be done.

Async. runsynchronAsync.RunSynchronously

Führt eine asynchrone Berechnung aus und wartet auf das Ergebnis des aufrufenden Threads.Runs an asynchronous computation and awaits its result on the calling thread. Dieser Befehl blockiert.This call is blocking.

Signatur:Signature:

computation: Async<'T> - timeout: ?int - cancellationToken: ?CancellationToken -> 'T

Verwendung:When to use it:

  • Wenn Sie ihn benötigen, verwenden Sie ihn nur einmal in einer Anwendung (am Einstiegspunkt einer ausführbaren Datei).If you need it, use it only once in an application - at the entry point for an executable.
  • Wenn Sie sich keine Gedanken über die Leistung machen und einen Satz anderer asynchroner Vorgänge gleichzeitig ausführen möchten.When you don't care about performance and want to execute a set of other asynchronous operations at once.

Zu überwachende Elemente:What to watch out for:

  • Der Aufruf von Async.RunSynchronously blockiert den aufrufenden Thread, bis die Ausführung abgeschlossen ist.Calling Async.RunSynchronously blocks the calling thread until the execution completes.

Async. StartAsync.Start

Startet eine asynchrone Berechnung im Thread Pool, die unitzurückgibt.Starts an asynchronous computation in the thread pool that returns unit. Wartet nicht auf das Ergebnis.Doesn't wait for its result. Mit Async.Start gestartete werden vollständig unabhängig von der übergeordneten Berechnung gestartet, die Sie aufgerufen hat.Nested computations started with Async.Start are started completely independently of the parent computation that called them. Ihre Lebensdauer ist nicht an eine übergeordnete Berechnung gebunden.Their lifetime is not tied to any parent computation. Wenn die übergeordnete Berechnung abgebrochen wird, werden keine untergeordneten Berechnungen abgebrochen.If the parent computation is canceled, no child computations are cancelled.

Signatur:Signature:

computation: Async<unit> - cancellationToken: ?CancellationToken -> unit

Nur verwenden, wenn:Use only when:

  • Sie verfügen über eine asynchrone Berechnung, die kein Ergebnis ergibt und/oder die Verarbeitung von einem Ergebnis erfordert.You have an asynchronous computation that doesn't yield a result and/or require processing of one.
  • Sie müssen nicht wissen, wenn eine asynchrone Berechnung abgeschlossen ist.You don't need to know when an asynchronous computation completes.
  • Der Thread, auf dem eine asynchrone Berechnung ausgeführt wird, ist nicht wichtig.You don't care which thread an asynchronous computation runs on.
  • Sie müssen keine Ausnahmen kennen, die sich aus der Aufgabe ergeben, oder Ausnahmen melden.You don't have any need to be aware of or report exceptions resulting from the task.

Zu überwachende Elemente:What to watch out for:

  • Ausnahmen, die mit Async.Start gestartet werden, werden nicht an den Aufrufer weitergegeben.Exceptions raised by computations started with Async.Start aren't propagated to the caller. Die Rückruf Stapel werden vollständig entwickelt.The call stack will be completely unwound.
  • Jede wirkungsvolle Arbeit (z. b. das Aufrufen von printfn), die mit Async.Start gestartet wird, führt nicht dazu, dass die Auswirkungen auf den Haupt Thread der Ausführung eines Programms auftreten.Any effectful work (such as calling printfn) started with Async.Start won't cause the effect to happen on the main thread of a program's execution.

Interoperabilität mit .netInteroperate with .NET

Möglicherweise arbeiten Sie mit einer .NET-Bibliothek C# oder-Codebasis, die asynchrone Programmierung mit asynchronem warteVorgang verwendet.You may be working with a .NET library or C# codebase that uses async/await-style asynchronous programming. Da C# und die Mehrzahl der .NET-Bibliotheken die Task<TResult> und Task Typen als Kern Abstraktionen anstelle Async<'T>verwenden, müssen Sie eine Grenze zwischen diesen beiden Ansätzen und Asynchronität überschreiten.Because C# and the majority of .NET libraries use the Task<TResult> and Task types as their core abstractions rather than Async<'T>, you must cross a boundary between these two approaches to asynchrony.

Arbeiten mit .NET ASYNC und Task<T>How to work with .NET async and Task<T>

Das Arbeiten mit asynchronen .NET-Bibliotheken und-Codebasen, die Task<TResult> verwenden (d. h. asynchrone Berechnungen mit F#Rückgabe Werten), ist unkompliziert und verfügt über integrierte Unterstützung für.Working with .NET async libraries and codebases that use Task<TResult> (that is, async computations that have return values) is straightforward and has built-in support with F#.

Sie können die Async.AwaitTask-Funktion verwenden, um auf eine asynchrone .net-Berechnung zu warten:You can use the Async.AwaitTask function to await a .NET asynchronous computation:

let getValueFromLibrary param =
    async {
        let! value = DotNetLibrary.GetValueAsync param |> Async.AwaitTask
        return value
    }

Sie können die Async.StartAsTask-Funktion verwenden, um eine asynchrone Berechnung an einen .net-Aufrufer zu übergeben:You can use the Async.StartAsTask function to pass an asynchronous computation to a .NET caller:

let computationForCaller param =
    async {
        let! result = getAsyncResult param
        return result
    } |> Async.StartAsTask

Arbeiten mit .NET ASYNC und TaskHow to work with .NET async and Task

Um mit APIs zu arbeiten, die Task verwenden (d. h. asynchrone .net-Berechnungen, die keinen Wert zurückgeben), müssen Sie möglicherweise eine zusätzliche Funktion hinzufügen, die eine Async<'T> in eine Taskkonvertiert:To work with APIs that use Task (that is, .NET async computations that do not return a value), you may need to add an additional function that will convert an Async<'T> to a Task:

module Async =
    // Async<unit> -> Task
    let startTaskFromAsyncUnit (comp: Async<unit>) =
        Async.StartAsTask comp :> Task

Es ist bereits eine Async.AwaitTask vorhanden, die eine Task als Eingabe akzeptiert.There is already an Async.AwaitTask that accepts a Task as input. Mit diesem und der zuvor definierten startTaskFromAsyncUnit Funktion können Sie Task Typen von einer F# asynchronen Berechnung aus starten und darauf warten.With this and the previously defined startTaskFromAsyncUnit function, you can start and await Task types from an F# async computation.

Beziehung zum MultithreadingRelationship to multi-threading

Obwohl Threading in diesem Artikel erwähnt wird, sind zwei wichtige Punkte zu beachten:Although threading is mentioned throughout this article, there are two important things to remember:

  1. Zwischen einer asynchronen Berechnung und einem Thread gibt es keine Affinität, es sei denn, Sie werden explizit im aktuellen Thread gestartet.There is no affinity between an asynchronous computation and a thread, unless explicitly started on the current thread.
  2. Die asynchrone Programmierung F# in ist keine Abstraktion für Multithreading.Asynchronous programming in F# is not an abstraction for multi-threading.

Eine Berechnung kann z. b. tatsächlich auf dem Thread des Aufrufers ausgeführt werden, je nach Art der Arbeit.For example, a computation may actually run on its caller's thread, depending on the nature of the work. Eine Berechnung könnte auch zwischen Threads springen und Sie für einen kurzen Zeitraum ableihen, um eine sinnvolle Arbeit zwischen den Zeitpunkten zu erreichen (z. b. bei der Übertragung eines Netzwerk Aufrufes).A computation could also "jump" between threads, borrowing them for a small amount of time to do useful work in between periods of "waiting" (such as when a network call is in transit).

Obwohl F# einige Möglichkeiten bietet, eine asynchrone Berechnung auf dem aktuellen Thread (oder explizit nicht auf dem aktuellen Thread) zu starten, ist Asynchronität in der Regel nicht mit einer bestimmten Threading Strategie verknüpft.Although F# provides some abilities to start an asynchronous computation on the current thread (or explicitly not on the current thread), asynchrony generally is not associated with a particular threading strategy.

Weitere InformationenSee also