{"id":17513007,"url":"https://github.com/symbolinker/awaitmultiple","last_synced_at":"2025-04-11T05:01:59.354Z","repository":{"id":258587692,"uuid":"875248126","full_name":"SymboLinker/AwaitMultiple","owner":"SymboLinker","description":"Await multiple tasks in parallel and get their return values with concise code.","archived":false,"fork":false,"pushed_at":"2024-10-29T04:39:25.000Z","size":45,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-11-05T09:08:45.925Z","etag":null,"topics":["async","await","csharp","dotnet","multiple","nuget","parallel","return","tasks","value","values"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"0bsd","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SymboLinker.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-19T13:34:09.000Z","updated_at":"2024-10-28T05:34:33.000Z","dependencies_parsed_at":"2024-11-28T21:44:31.058Z","dependency_job_id":null,"html_url":"https://github.com/SymboLinker/AwaitMultiple","commit_stats":{"total_commits":20,"total_committers":2,"mean_commits":10.0,"dds":0.09999999999999998,"last_synced_commit":"49b6c2d49bdce0239100ccdc7455fa4c29454e7b"},"previous_names":["symbolinker/awaitmultiple"],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SymboLinker%2FAwaitMultiple","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SymboLinker%2FAwaitMultiple/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SymboLinker%2FAwaitMultiple/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SymboLinker%2FAwaitMultiple/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SymboLinker","download_url":"https://codeload.github.com/SymboLinker/AwaitMultiple/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228740058,"owners_count":17965180,"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","await","csharp","dotnet","multiple","nuget","parallel","return","tasks","value","values"],"created_at":"2024-10-20T06:06:41.674Z","updated_at":"2024-12-08T14:10:07.094Z","avatar_url":"https://github.com/SymboLinker.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![NuGet](https://img.shields.io/nuget/vpre/AwaitMultiple.svg)](https://www.nuget.org/packages/AwaitMultiple)\r\n\r\n# AwaitMultiple\r\n\r\nAwait multiple tasks in parallel and get their return values with concise code.\r\n\r\n\r\n## How to use and why\r\n\r\nAwaitMultiple can be used like this up to 16 arguments:\r\n```cs\r\nvar (value1, value2, value3) = await Tasks(task1, task2, task3);\r\n```\r\n\r\nAdd:\r\n```cs\r\nglobal using static AwaitMultiple.__Await;\r\n```\r\n\r\nWrite\r\n```cs\r\nvar (books, employees) = await Tasks(\r\n   dbConnection.GetAllAsync\u003cBooks\u003e(),\r\n   dbConnection.GetAllAsync\u003cEmployees\u003e());\r\n```\r\ninstead of\r\n```cs\r\nvar books = await dbConnection.GetAllAsync\u003cBook\u003e();\r\nvar employees = await dbConnection.GetAllAsync\u003cEmployee\u003e();\r\n```\r\nbecause the latter code is not executing the employees-related task until the books-related task has finished.\r\n\r\n\r\n## Optional feature\r\nAwait tasks with and without return value in a single call:\r\n```cs\r\nvar (books, employees) = await Tasks(\r\n   dbConnection.GetAllAsync\u003cBooks\u003e(),\r\n   dbConnection.GetAllAsync\u003cEmployees\u003e(),\r\n   [\r\n      dbConnection.InsertHistoryRecordAsync(),\r\n      // ... any number of tasks...\r\n   ]);\r\n```\r\nor\r\n```cs\r\nvar books = await Tasks(\r\n   dbConnection.GetAllAsync\u003cBooks\u003e(),\r\n   [\r\n      dbConnection.InsertHistoryRecordAsync(),\r\n      // ... any number of tasks...\r\n   ]);\r\n```\r\nFor code consistency, you can also use:\r\n```cs\r\nawait Tasks([\r\n   dbConnection.InsertHistoryRecordAsync(),\r\n   // ... any number of tasks...\r\n]);\r\n```\r\n\r\n\r\n## Exception handling options\r\n\r\nBy default, only the first occurring exception is thrown (and the others are caught but not re-thrown).\r\nThis is consistent with `Task.WhenAll` and more parts of the C# language.\r\n\r\n### Continue if one task fails\r\nYou may want to continue if \"getting value `b`\" fails. In that case, you could use the NuGet package [TaskExceptionCatcher](https://github.com/Symbolinker/TaskExceptionCatcher#readme) like this:\r\n```cs\r\nvar (a, catchResultB, c) = await Tasks(\r\n   StartTaskAAsync(),\r\n   Catcher.Run(() =\u003e StartTaskBAsync()),\r\n   StartTaskCAsync());\r\nif (catchResultB.Exception is { } exception)\r\n{\r\n   // no problem!\r\n}\r\nelse\r\n{\r\n   var b = catchResultB.Value;\r\n   // use `b`.\r\n}\r\n\r\n// use `a` and `c`.\r\n```\r\n\r\n### Getting all the exceptions\r\nIf you're interested in not only the first, but all the exceptions:\r\n- set the `exceptionOption` to `ExceptionOption.Aggregate`\r\n- use `Task.Run` on all arguments, all tasks.\r\n```cs\r\nvar (a, b) = await Tasks(\r\n   Task.Run(() =\u003e StartTaskAAsync()),\r\n   Task.Run(() =\u003e StartTaskBAsync()),\r\n   exceptionOption: ExceptionOption.Aggregate);\r\n```\r\nThen all errors are returned in a single `AggregateException`. Its `Message` property is like:\r\n\r\n\u003e One or more errors occurred. (First exception message.) (Second exception message.)\r\n\r\nUse the property `aggregateException.InnerExceptions` for more details like `StackTrace`s etc.\r\n\r\nWhy is `Task.Run` needed? Because `async` functions don't return a task until the first `await` keyword.\r\nIf an exception occurs before that, then that function throws even before it passes an argument into `Tasks`.\r\n\r\n\r\n## Configuring awaits\r\n\r\n**This section is for nerds only. Using `ConfigureAwait` is NOT necessary.**\r\n\r\nAwaitMultiple uses `.ConfigureAwait(false)` internally. Programmers using AwaitMultiple in their own library can use `.ConfigureAwait(false)`:\r\n```cs\r\nvar (books, employees) = await Tasks(\r\n   dbConnection.GetAllAsync\u003cBooks\u003e(),\r\n   dbConnection.GetAllAsync\u003cEmployees\u003e())\r\n   .ConfigureAwait(false);\r\n```\r\n\r\nMore details:\r\n- The above is slightly better for performance. Normally, after having `await`ed an async operation, the \"context\" is set to the same as before the `await`. That costs time. In most libraries there is no need to capture and return to a specific context, so one might want to set `continueOnCapturedContext` to `false` in those libraries.\r\n- Library writers using the above also avoid some deadlock problems for consumers that use their library wrongly.\r\n- In app-level code you will probably not see `.ConfigureAwait(false)` being used. The performance gain is very small.\r\n- One must not use `.ConfigureAwait(false)` in a method body that interacts with UI. It is fine to never use it at all.\r\n- Writing `await task.ConfigureAwait(true);` is functionally identical to `await task;`, so you never need to use `.ConfigureAwait(true)`.\r\n\r\n**Conclusion for consumers of this library**:\r\nYou don't need to use `ConfigureAwait` at all unless you're writing your own library code and want extra performance.\r\n\r\n\r\n## Get it\r\n\r\nAvailable via [NuGet](https://www.nuget.org/packages/AwaitMultiple).\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsymbolinker%2Fawaitmultiple","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsymbolinker%2Fawaitmultiple","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsymbolinker%2Fawaitmultiple/lists"}