{"id":17037213,"url":"https://github.com/tomblind/unity-async-routines","last_synced_at":"2025-10-27T14:19:35.278Z","repository":{"id":217165070,"uuid":"157224693","full_name":"tomblind/unity-async-routines","owner":"tomblind","description":"A replacement for Unity coroutines using C#7's async/await","archived":false,"fork":false,"pushed_at":"2024-03-25T22:57:46.000Z","size":63,"stargazers_count":77,"open_issues_count":2,"forks_count":11,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-12T12:43:57.021Z","etag":null,"topics":["async","await","coroutines","routines","unity","unity-3d"],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tomblind.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"zenodo":null}},"created_at":"2018-11-12T14:18:40.000Z","updated_at":"2025-01-31T17:39:04.000Z","dependencies_parsed_at":"2025-04-12T12:34:11.902Z","dependency_job_id":"722b3c74-6989-4ee9-8ae3-596b2513119c","html_url":"https://github.com/tomblind/unity-async-routines","commit_stats":null,"previous_names":["tomblind/unity-async-routines"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/tomblind/unity-async-routines","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomblind%2Funity-async-routines","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomblind%2Funity-async-routines/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomblind%2Funity-async-routines/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomblind%2Funity-async-routines/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tomblind","download_url":"https://codeload.github.com/tomblind/unity-async-routines/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomblind%2Funity-async-routines/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265180440,"owners_count":23723687,"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","coroutines","routines","unity","unity-3d"],"created_at":"2024-10-14T08:53:10.505Z","updated_at":"2025-10-27T14:19:34.818Z","avatar_url":"https://github.com/tomblind.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Unity AsyncRoutines\n\nA \"spiritual successor\" to [Unity Routines](https://github.com/tomblind/unity-routines), AsyncRoutines is a replacement for Unity's coroutines that makes use of C# 7's async functions (available in Unity 2018.3).\n\nNotable Features Include\n- A manager component that can run routines and ensure they are stopped when the GameObject is destroyed\n- Hierarchical support to allow awaiting collections of routines (WaitForAll/WaitForAny)\n- Built-in support for passing AsyncOperations and CustomYieldInstructions to await\n- Utilizes a custom async task builder and extensive pooling to keep routines efficient and reduce garbage\n\nThere is also an extension [Unity AsyncTweens](https://github.com/tomblind/unity-async-tweens) which adds a set of tweening routines that can be used in Async Routines.\n\n## Basic Usage\n```cs\nusing UnityEngine;\nusing AsyncRoutines;\n\npublic class MyObject : MonoBehaviour\n{\n    public RoutineManagerBehavior routineManager;\n\n    public void Start()\n    {\n        routineManager.Run(Countdown());\n    }\n\n    public async Routine Countdown()\n    {\n        for (var i = 10; i \u003e= 0; --i)\n        {\n            Debug.Log(i);\n            await Routine.WaitForSeconds(1);\n        }\n    }\n}\n```\n\nRoutineManagerBehavior is a component which manages routines for a specific object. All routines started with Run will be shut down when the object is destroyed. Run also returns a handle which allows individual routines to be stopped manually.\n\nRoutine provides a suite of WaitFor* methods for use in 'async Routine' methods. Note that to use certain WaitFor methods, a routine must be \"managed\". That means it, or one of its ancestors, must have been started with RoutineManager.Run().\n\n## Waiting on Multiple Routines\n```cs\n//Resumes when all sub-routines complete\npublic async Routine DoAllOfTheThings()\n{\n    await Routine.WaitForAll(DoThingOne(), DoThingTwo(), DoThingThree());\n}\n\n//Resumes when the first sub-routine completes (and shuts down the rest)\npublic async Routine DoAnyOfTheThings()\n{\n    await Routine.WaitForAny(DoThingOne(), DoThingTwo(), DoThingThree());\n}\n\npublic async Routine DoThingOne() { ... }\npublic async Routine DoThingTwo() { ... }\npublic async Routine DoThingThree() { ... }\n```\n\n## Return Values\n```cs\npublic async Routine PrintTheNumber()\n{\n    var theNum = await GetTheNumber();\n    Debug.Log(theNum);\n}\n\npublic async Routine\u003cint\u003e GetTheNumber()\n{\n    await Routine.WaitForSeconds(1);\n    return 17;\n}\n```\n\n```cs\npublic async Routine PrintAllOfTheNumbers()\n{\n    //numbers is an int[] containing all of the results in order\n    var numbers = await Routine.WaitForAll(GetTheFirstNumber(), GetTheSecondNumber(), GetTheThirdNumber());\n    foreach (var num in numbers)\n    {\n        Debug.Log(num);\n    }\n}\n\npublic async Routine PrintAnyOfTheNumbers()\n{\n    //num is the result of the first routine to finish\n    var num = await Routine.WaitForAny(GetTheFirstNumber(), GetTheSecondNumber(), GetTheThirdNumber());\n    Debug.Log(num);\n}\n\npublic async Routine\u003cint\u003e GetTheFirstNumber()\n{\n    await Routine.WaitForSeconds(3);\n    return 1;\n}\n\npublic async Routine\u003cint\u003e GetTheSecondNumber()\n{\n    await Routine.WaitForSeconds(2);\n    return 2;\n}\n\npublic async Routine\u003cint\u003e GetTheThirdNumber()\n{\n    await Routine.WaitForSeconds(1);\n    return 3;\n}\n```\n\n## Waiting on Event/Callbacks\nAsyncRoutines provides the helper type IResumer to allow for awaiting events/callbacks.\n```cs\npublic IResumer resumer = null;\n\npublic async Routine WaitForCallback()\n{\n    resumer = Routine.GetResumer();\n    await resumer;\n    Routine.ReleaseResumer(resumer);\n    resumer = null;\n}\n\npublic void OnCallback()\n{\n    resumer.Resume();\n}\n```\n```cs\nUnityEvent unityEvent;\n\npublic async Routine WaitForUnityEvent()\n{\n    var resumer = Routine.GetResumer();\n    unityEvent.AddListener(resumer.Resume);\n    await resumer;\n    Routine.ReleaseResumer(resumer);\n}\n```\n```cs\nevent Action\u003cstring\u003e strEvent;\n\npublic async Routine WaitForEventWithString()\n{\n    var resumer = Routine.GetResumer\u003cstring\u003e();\n    strEvent += resumer.Resume;\n    var result = await resumer;\n    Routine.ReleaseResumer(resumer);\n    Debug.Log(result);\n}\n```\nNotice that IResumers are pooled and should be released when not needed. However, they can be re-used multiple times without being released.\n\nIResumers are also \"smart\" about being called before being awaited upon.\n```cs\npublic async Routine DoTheThing()\n{\n    var resumer = Routine.GetResumer();\n    StartTheThing(resumer.Resume); //Could call resumer.Resume immediately\n    await resumer; //Detects that resumer was already called and doesn't wait\n    Routine.ReleaseResumer(resumer);\n}\n\npublic void StartTheThing(Action finishCallback)\n{\n    finishCallback(); //Finishes immediately\n}\n```\nIn this example, resumer.Resume() gets called before being awaited on. In this case it's 'marked' as resumed and the await statement will resume immediately.\n\n## Cleanup and Error Handling\nRun() takes an optional onStop callback, which is always called when a routine ends, regardless of how it ended. This is a good place to do any cleanup. It is passed an Exception as its only argument. If the routine threw an unhandled exception, it will be received there. Otherwise it will be null. If onStop is not set and an exception occurs, it will be reported using Unity's Debug.LogException.\n\nCall stacks in exceptions from async routines are not very useful. To help with this, set Routine.EnableTracing to true. This will add additional info to the exception to help trace where it came from. But, there's a small performance hit for using this, so it is off by default.\n\n## Using Routines Outside of Behaviours\nRoutineManagerBehavior is a simple wrapper around a RoutineManager object. If you want to manage your own routines without using a component, you can use RoutineManager to do so, but you must call Update(), Flush() and StopAll() yourself at appropriate times. Flush() should be called after all Updates (usually in LateUpdate).\n\n## Notes\n- Be careful not to await a Routine from a standard 'async Task' function (unless that was awaited from a routine higher up). The routine won't be associated with a manager and certain WaitFor functions will not work.\n- Routines are not thread-safe. You can await on multi-threaded tasks from a routine, but do not use routines in more than one thread at once.\n- Routines, resumers and the underlying state machines are all pooled. This means a sudden burst of usage of many routines can cause memory usage to increase permenantly. You can use Routine.ClearPools() to dump pooled objects at strategic times (like between scene loads) if this becomes problematic.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomblind%2Funity-async-routines","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftomblind%2Funity-async-routines","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomblind%2Funity-async-routines/lists"}