{"id":13779260,"url":"https://github.com/kekyo/FSharp.Control.FusionTasks","last_synced_at":"2025-05-11T12:33:05.373Z","repository":{"id":50253169,"uuid":"53183463","full_name":"kekyo/FSharp.Control.FusionTasks","owner":"kekyo","description":"F# Async workflow \u003c--\u003e .NET Task/ValueTask easy seamless interoperability library.","archived":false,"fork":false,"pushed_at":"2022-11-12T13:57:38.000Z","size":2648,"stargazers_count":160,"open_issues_count":1,"forks_count":13,"subscribers_count":11,"default_branch":"main","last_synced_at":"2024-11-09T10:31:49.113Z","etag":null,"topics":["async","async-enumerable","csharp","dotnet","fsharp","interoperability","task","valuetask"],"latest_commit_sha":null,"homepage":"","language":"F#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kekyo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-03-05T04:34:06.000Z","updated_at":"2024-11-04T23:44:09.000Z","dependencies_parsed_at":"2023-01-22T20:15:20.234Z","dependency_job_id":null,"html_url":"https://github.com/kekyo/FSharp.Control.FusionTasks","commit_stats":null,"previous_names":[],"tags_count":37,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekyo%2FFSharp.Control.FusionTasks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekyo%2FFSharp.Control.FusionTasks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekyo%2FFSharp.Control.FusionTasks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kekyo%2FFSharp.Control.FusionTasks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kekyo","download_url":"https://codeload.github.com/kekyo/FSharp.Control.FusionTasks/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224461876,"owners_count":17315116,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","async-enumerable","csharp","dotnet","fsharp","interoperability","task","valuetask"],"created_at":"2024-08-03T18:01:03.199Z","updated_at":"2024-11-17T14:31:17.595Z","avatar_url":"https://github.com/kekyo.png","language":"F#","funding_links":[],"categories":["Concurrent, Asynchronous, and Parallel Programming"],"sub_categories":[],"readme":"# F# FusionTasks\n\n![FusionTasks](https://raw.githubusercontent.com/kekyo/FSharp.Control.FusionTasks/master/Images/FSharp.Control.FusionTasks.128.png)\n\n## Status\n\n| | main | devel |\n|:---|:--:|:--:|\n| NuGet Package | [![NuGet FusionTasks](https://img.shields.io/nuget/v/FSharp.Control.FusionTasks.svg?style=flat)](https://www.nuget.org/packages/FSharp.Control.FusionTasks) | |\n| Continuous integration | [![RelaxVersioner CI build (main)](https://github.com/kekyo/FSharp.Control.FusionTasks/workflows/.NET/badge.svg?branch=main)](https://github.com/kekyo/FSharp.Control.FusionTasks/actions) | [![RelaxVersioner CI build (main)](https://github.com/kekyo/FSharp.Control.FusionTasks/workflows/.NET/badge.svg?branch=devel)](https://github.com/kekyo/FSharp.Control.FusionTasks/actions) |\n\n-----\n\n## What is this?\n\n* F# Async workflow \u003c--\u003e .NET Task/ValueTask easy seamless interoperability library.\n* Sample code (F# side):\n\n``` fsharp\nlet asyncTest = async {\n  use ms = new MemoryStream()\n\n  // FusionTasks directly interpreted System.Threading.Tasks.Task class in F# async-workflow block.\n  do! ms.WriteAsync(data, 0, data.Length)\n  do ms.Position \u003c- 0L\n\n  // FusionTasks directly interpreted System.Threading.Tasks.Task\u003cT\u003e class in F# async-workflow block.\n  let! length = ms.ReadAsync(data2, 0, data2.Length)\n  do length |\u003e should equal data2.Length\n}\n```\n\n* Sample code (C# side):\n\n``` csharp\nusing System.Threading.Tasks;\nusing Microsoft.FSharp.Control;\n\npublic async Task AsyncTest(FSharpAsync\u003cint\u003e asyncIntComp)\n{\n  // FusionTasks simple usage F#'s Async\u003cunit\u003e direct awaitable.\n  await FSharpAsync.Sleep(500);\n  Console.WriteLine(\"Awaited F# async function (unit).\");\n\n  // FusionTasks simple usage F#'s Async\u003cint\u003e direct awaitable.\n  var result = await asyncIntComp;\n  Console.WriteLine(\"Awaited F# async function: Result=\" + result);\n}\n```\n\n-----\n\n## Features\n\n* Easy interoperable .NET Task/ValueTask \u003c--\u003e F#'s Async.\n* F# async workflow block now supports directly .NET Task/ValueTask handle with let!, do! and use!.\n* .NET (C# async-await) now supports directly F#'s Async.\n* SyncronizationContext capture operation support (F#: AsyncConfigure method / .NET (C#) AsAsyncConfigured method)\n* .NET now supports standard asynchronous sequence called `IAsyncEnumerable\u003cT\u003e`, FusionTasks supports it with `for` expression.\n\n## Benefits\n\n* Easy interoperability, combination and relation standard .NET OSS packages using Task/ValueTask and F#'s Async.\n* F# 6.0/4.5 with .NET 6.0/5.0, .NET Core 3.0/2.0 (or higher), .NET Standard 1.6/2.0 and .NET Framework 4.5/4.6.1/4.8.\n* Ready to LINQPad 5.\n\n-----\n\n## Environments\n\n* F# 6.0 or higher/4.5\n* .NET 6.0\n* .NET 5.0\n* .NET Core 3.0/2.0 or higher\n* .NET Standard 1.6/2.0/2.1\n* .NET Framework 4.5/4.6.1/4.8\n\nCombination chart:\n\n| .NET BCL | F# | Details |\n|:----|:----|:----|\n| .NET 6.0 | F# 6.0 or higher | |\n| .NET 5.0 | F# 6.0 or higher | |\n| .NET Core 3.1, 3.0 | F# 6.0 or higher | (3.0 is deprecated) |\n| .NET Core 2.,2 2.1, 2.0 | F# 6.0 or higher | (2.0 is deprecated) |\n| .NET Standard 2.1, 2.0 | F# 6.0 or higher | |\n| .NET Standard 1.6 | F# 4.5 | |\n| .NET Framework 4.8, 4.6.1 | F# 6.0 or higher | |\n| .NET Framework 4.5 | F# 4.5 | |\n\n-----\n\n## How to use\n\n* Search NuGet package and install \"FSharp.Control.FusionTasks\".\n* F# use, autoopen'd namespace \"FSharp.Control\". \"System.Threading.Tasks\" is optional.\n* C# use, using namespace \"System.Threading.Tasks\". \"Microsoft.FSharp.Control\" is optional.\n\n## Samples\n\n### Basic async workflow:\n\n``` fsharp\nlet asyncTest = async {\n  use ms = new MemoryStream()\n\n  // FusionTasks directly interpreted System.Threading.Tasks.Task class in F# async-workflow block.\n  // Sure, non-generic Task mapping to Async\u003cunit\u003e.\n  do! ms.WriteAsync(data, 0, data.Length)\n  do ms.Position \u003c- 0L\n\n  // FusionTasks directly interpreted System.Threading.Tasks.Task\u003cT\u003e class in F# async-workflow block.\n  // Standard usage, same as manually used Async.AwaitTask.\n  let! length = ms.ReadAsync(data2, 0, data2.Length)\n  do length |\u003e should equal data2.Length\n}\n```\n\n### Without async workflow:\n\n``` fsharp\nuse ms = new MemoryStream()\n\n// Manually conversion by an operator \"Async.AsAsync\" : Task\u003cT\u003e --\u003e Async\u003c'T\u003e\nlet asy = ms.ReadAsync(data, 0, data.Length) |\u003e Async.AsAsync\nlet length = asy |\u003e Async.RunSynchronosly\n```\n\n### Without async workflow (CancellationToken):\n\n``` fsharp\nuse ms = new MemoryStream()\nlet cts = new CancellationTokenSource()\n\n// Produce with CancellationToken:\n// TIPS: FusionTasks cannot handle directly CancellationToken IN ASYNC WORKFLOW.\n//   Because async workflow semantics implicitly handled CancellationToken with Async.DefaultCancellationToken, CancellationToken and CancelDefaultToken().\n//   (CancellationToken derived from Async.StartWithContinuations() in async workflow.)\nlet asy = ms.ReadAsync(data, 0, data.Length).AsAsync(cts.Token)\nlet length = asy |\u003e Async.RunSynchronosly\n```\n\n### Handle Task.ConfigureAwait(...)  (Capture/release SynchContext):\n\n``` fsharp\nlet asyncTest = async {\n  use ms = new MemoryStream(...)\n\n  // We can use ConfigureAwait() on let!/do!.\n  let! length = ms.ReadAsync(data, 0, data.Length).ConfigureAwait(false)\n}\n```\n\nNOTE: Older released contains `AsyncConfigure(bool)` method, but it was obsoleted.\nBecause it existed for avoiding PCL strange linking errors.\n\n### Delegate async continuation - works like TaskCompletionSource\u0026lt;T\u0026gt;:\n\n``` fsharp\nopen System.Threading\n\nlet asyncCalculate() =\n  // Create AsyncCompletionSource\u003c'T\u003e.\n  let acs = new AsyncCompletionSource\u003cint\u003e()\n\n  // Execution with completely independent another thread...\n  let thread = new Thread(new ThreadStart(fun _ -\u003e\n    Thread.Sleep(5000)\n    // If you captured thread context (normally continuation or callbacks),\n    // can delegation async continuation using AsyncCompletionSource\u003c'T\u003e.\n    acs.SetResult(123 * 456)))\n  thread.Start()\n\n  // Async\u003c'T\u003e instance\n  acs.Async\n```\n\n### Standard asynchronous sequence IAsyncEnumerable\u0026lt;T\u0026gt;:\n\n``` fsharp\nlet asyncTest = async {\n  // FusionTasks directly interpreted System.Collection.Generic.IAsyncEnumerable\u003cT\u003e in\n  // F# async-workflow for expression.\n  for value in FooBarAccessor.EnumerableAsync() do\n    // Totally asynchronous operation in each asynchronous iteration:\n    let! result = value |\u003e FooBarCollector.calculate\n    do! output.WriteAsync(result)\n\n  // ... (Continuation is asynchronously behind `for` loop)\n}\n```\n\nAnd, we can use `IAsyncEnumerable\u003cT\u003e.ConfigureAwait(bool)` on it.\n\nNOTE: `IAsyncEnumerable\u003cT\u003e` is supported only these environments:\n\n* net461 or higher.\n* netstandard2.0 or higher.\n* netcoreapp2.1 or higher.\n\nIt limitation comes from [NuGet Microsoft.Bcl.AsyncInterfaces 5.0.0.](https://www.nuget.org/packages/Microsoft.Bcl.AsyncInterfaces/)\n\n### Standard asynchronous disposer IAsyncDisposable:\n\n``` fsharp\nlet asyncTest = async {\n  // FusionTasks directly interpreted System.IAsyncDisposable in\n  // F# async-workflow use expression.\n  // TIP: We can use `use` expression instead of `use!`,\n  // Because the `use!` will be bound asynchronously BEFORE calling `DisposeAsync()`.\n  use accessor = DatabaseAccessor.getAsyncDisposableAccessor()\n\n  // (Use accessor...)\n\n  // (Will be disposed asynchronously, calls `DisposeAsync()` at end of scope...)\n}\n```\n\n### TIPS: We have to add annotation for arguments if using it in async workflow:\n\n``` fsharp\nlet asyncInner arg0 = async {\n  // Cause FS0041:\n  //   A unique overload for method 'Source' could not be determined based on type information prior to this program point.\n  //   A type annotation may be needed.\n  //  --\u003e Because F# compiler conflict arg0 type inferences: Async\u003cint\u003e or Task\u003cint\u003e.\n  let! result = arg0\n  let calculated = result + 1\n  printfn \"%d\" calculated\n}\n\n// Fixed with type annotation Async\u003c'T\u003e or Task\u003c'T\u003e:\nlet asyncInner (arg0:Async\u003c_\u003e) = async {\n  let! result = arg0\n  let calculated = result + 1\n  printfn \"%d\" calculated\n}\n```\n\n### In C# side:\n\n* Really need sample codes? huh? :)\n\n-----\n\n### Easy LINQPad 5 driven:\n\n* Before setup NuGet package (FSharp.Control.FusionTasks) the LINQPad NuGet Manager.\n\n``` fsharp\nopen System.IO\n\n// Result is Async\u003cbyte[]\u003e\nlet asyncSequenceData =\n  let r = new Random()\n  let data = [| for i = 1 to 100 do yield byte (r.Next()) |]\n  async {\n    use fs = new MemoryStream()\n    do! fs.WriteAsync(data, 0, data.Length)\n    do! fs.FlushAsync()\n    return fs.ToArray()\n  }\n\n// Convert to Task\u003cbyte[]\u003e and dump:\nasyncSequenceData.AsTask().Dump()\n```\n\n![LINQPad 5 driven](https://raw.githubusercontent.com/kekyo/FSharp.Control.FusionTasks/master/Images/linqpad5.png)\n\n-----\n\n## \"task-like\" and ValueTask appendix\n\n* .NET add new \"task-like\" type. \"task-like\" means applied a attribute \"System.Runtime.CompilerServices.AsyncMethodBuilderAttribute\" and declared the async method builder.\n* ValueTask overview:\n  * New standard \"task-like\" type named for \"ValueTask\u0026lt;T\u0026gt;\" for C#. FusionTasks supported ValueTask\u0026lt;T\u0026gt; on 1.0.20.\n  * ValueTask\u0026lt;T\u0026gt; declared by struct (Value type) for goal is improvement performance. But this type has the Task\u0026lt;T\u0026gt; instance inside and finally continuation handle by Task\u0026lt;T\u0026gt;.\n  * ValueTask\u0026lt;T\u0026gt; performance effective situation maybe chatty-call fragments using both caller C# and awaiter C# code...\n  * ValueTask\u0026lt;T\u0026gt; a little bit or no effect improvement performance, because usage of senario for FusionTasks.\n* \"task-like\" augumenting is difficult:\n  * We have to apply to task-like type with the attribute \"AsyncMethodBuilderAttribute\".\n  * Means if already declared type (Sure, we have FSharpAsync\u0026lt;'T\u0026gt;) cannot augument and cannot turn to task-like type.\n  * Therefore cannot directly return for FSharpAsync\u0026lt;'T\u0026gt; from C#'s async-await method.\n  * And cannot auto handle task-like type by FusionTasks, because no type safe declaration for task-like type...\n    * For example, if force support task-like type, FusionTasks require augument \"Source: taskLike: obj -\u003e FSharpAsync\u0026lt;'T\u0026gt;\" overload on FSharpAsync\u0026lt;'T\u0026gt;. This cannot type safe.\n* Conclusion:\n  * So FusionTasks support only \"ValueTask\u0026lt;T\u0026gt;\" type and cannot support any other \"task-like\" types.\n\n## Additional resources\n\n* Source codes available only \"FSharp.Control.FusionTasks\" folder.\n* The slides: \"How to meets Async and Task\" in Seattle F# Users group \"MVP Summit Special: A Night of Lightning Talks\" 2016.11.09 http://www.slideshare.net/kekyo/asyncs-vs-tasks\n\n\u003ciframe src=\"https://www.slideshare.net/slideshow/embed_code/68424602\" width=\"800\" height=\"500\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"\u003e\u003c/iframe\u003e\n\n## TODO\n\n Improvements more easier/effective interfaces.\n\n-----\n\n## License\n\n* Copyright (c) 2016-2022 Kouji Matsui (@kozy_kekyo)\n* Under Apache v2 http://www.apache.org/licenses/LICENSE-2.0\n\n## History\n\n* 2.6.0:\n  * Final version. Thank you using FusionTasks!\n  * You are ready to use both FusionTasks and F# 7.0! See [issue #14](https://github.com/kekyo/FSharp.Control.FusionTasks/issues/14).\n  * Added supporting .NET Core 2.2 environments.\n  * Minimized package dependency.\n* 2.5.0:\n  * Supported .NET 6.0 and F# 6.0 environment.\n* 2.4.0:\n  * Supported varies for operator `Async.AsAsync`.\n  * Completed supporting configured capturing context method `ConfigureAwait(bool)` on all Task based instances.\n* 2.3.3:\n  * Supported .NET asynchronous disposer (`IAsyncDisposable`).\n  * Supported releasing synchronization context by `IAsyncEnumerable\u003cT\u003e.ConfigureAwait(bool)`.\n  * Fixed minor exception leaking at the continuation for asynchronous sequence.\n* 2.3.0:\n  * Supported .NET asynchronous sequence (`IAsyncEnumerable` and essential types).\n* 2.2.0:\n  * Suppressed Task/ValueTask allocation when they were already completed (#12, @danielmarbach)\n* 2.1.1:\n  * Downgraded FSharp.Core requirements from 5.0.1 to 5.0.0.\n* 2.1.0:\n  * Added .NET 5, .NET Core 3 and .NET Framework 4.8 assemblies.\n  * Fixed capturing synchronization context at the asynchronous continuations.\n* 2.0.2:\n  * Fixed add xml comments into package.\n* 2.0.1:\n  * Add support ValueTask for non-generic version.\n  * Fixed XML comments.\n* 2.0.0:\n  * Supported F# 4.5, .NET Standard 2.0 and .NET Core 2.0.\n  * Sorry, archived all PCL's libraries. Now FusionTasks supports only .NET Framework 4.5, .NET Core 2.0 and .NET Standard 1.6/2.0.\n  * Solution structure refablished. Changed to .NET Core modern-style.\n* 1.1.1:\n  * Add ValueTask\u003c'T\u003e bind source overload.\n* 1.1.0:\n  * Supported F# 4.1 and .NET Standard 1.6. (Unfortunately deprecated FS40.netcore (netstandard1.4) package, try to migrate to F# 4.1 :)\n* 1.0.20:\n  * Support ValueTask\u0026lt;T\u0026gt; (Exclude net40 and Profile 47 platform, added dependency for System.Threading.Tasks.Extensions).\n  * Update version for .NET Core F# (1.0.0-alpha-161205).\n* 1.0.13:\n  * Reduce to only contains .NET Core's assembly in FS40.netcore package.\n  * Refactor folder structures.\n* 1.0.12:\n  * Add .NET Core support (Separated package: FSharp.Control.FusionTasks.FS40.netcore with -Pre option required)\n* 1.0.2:\n  * Support 'for .. in' expressions. (Thx Armin!)\n* 1.0.1:\n  * Fixed cause undefined Async\u0026lt;'T\u0026gt; using combination Async\u0026lt;'T\u0026gt; and Task/Task\u0026lt;T\u0026gt; in async workflow. (Thx Honza!)\n* 1.0.0:\n  * RTM release :clap:\n  * Add FSharp.Core NuGet references.\n  * Temporary disable support .NET Core. If reached F# RTM, continue development... (PR welcome!!)\n  * Add sample codes.\n* 0.9.6:\n  * WIP release.\n* 0.9.5:\n  * WIP release.\n* 0.9.4:\n  * Fixed nuspec reference System, System.Core\n* 0.9.3:\n  * Fixed nuspec frameworkAssemblies.\n* 0.9.2:\n  * Add package targetFramework.\n  * Updated RelaxVersioner.\n* 0.9.1:\n  * Remove strongly-signed (Unit test doesn't work...)\n  * Omit synchronizers (AsyncLock, AsyncLazy). Thats moving to FSharp.Control.AsyncPrimitives project (https://github.com/kekyo/FSharp.Control.AsyncPrimitives).\n  * Add target dnxcore50 into F# 4.0 (for .NET Core 1.0)\n  * Source codes and documents bit changed.\n* 0.5.8:\n  * Add strongly-signed.\n* 0.5.7:\n  * Add PCL Profile 7.\n* 0.5.6:\n  * Add PCL Profile 78.\n  * Fixed minor PCL moniker fragments.\n* 0.5.5:\n  * Fixed version number.\n  * Fixed icon image url.\n* 0.5.4:\n  * Auto open FSharp.Control.\n  * Manage AppVeyor CI.\n* 0.5.3: Implement awaiter classes.\n* 0.5.2: Add dependency assemblies.\n* 0.5.1: NuGet package support.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkekyo%2FFSharp.Control.FusionTasks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkekyo%2FFSharp.Control.FusionTasks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkekyo%2FFSharp.Control.FusionTasks/lists"}