dotnet / dotnet/vblang

Proposal: Improving async support for better cooperation between sync and async functions

Open
#426 8 comments 0 reactions 0 assignees View on GitHub
Dominant language
No language data
Stars
328
Forks
71
PR merge metrics
No merged PRs in 30d

Description

Async support is great feature, but there is well known problem with mixing sync and async functions. Handling async procedures form sync procedures is very unpleasant and dangerous (deadlocks), while switching most sync code to async variant is equally problematic and non-practical. To enable better cooperation between sync and async procedures, there is need to create universal functions, that can be used with sync and async calls.

```
Dim data() As Byte
Public Function ReadFromDisk () As Boolean
data = Await GetFile() ' GetFile return Taks(Of Byte())
Return True
End Function
```

Because this function use await, then is implemented similar to current async functions: creates internal task with state machine, (IAsyncStateMachine). Additionally, such function is aware of external service. If such service exist, then function register their internal task to that service and return nothing. If service do not exist, then executes internal task synchronously to the end, and return result from finished task.

With updated model, service is set for calls with Await keyword, but only for these functions, that can register their internal task. After acquiring task from called universal function, global service is removed. This is alternative way to get task from called function, to current approach where task is grabbed via direct return.

Global service is stack-based, where every thread have separated stack.

Examples how this function and caller work.

Call from synchronous function:

```
Public Function LoadData () As Boolean
ReadFromDisk()
Return True
End Function
```

LoadData is synchronous, so service is not set, and ReadFromDisk execute their task internally and return result to the caller.

Call from universal function in synchronous way. LoadData is called from other synchronous function:

```
Public Function LoadData () As Boolean
Await ReadFromDisk()
Return True
End Function
```

Inside this function, Await sets global service. Called function (ReadFromDisk) detect this service, and register internal task to that service. After registering, called function returns Nothing. With acquired task function (LoadData) do not return their own task to the synchronous caller, but wait when acquired task is completed, then executes their own continuation (return True).

If this function (LoadData) is called from async caller, then register their own task to global service, register itself to grabbed task (really awaiter) and return Nothing..

Call from async function:

```
Public Async Function LoadData() As Task(Of Boolean)
Await ReadFromDisk()
Return True
End Function
```

As above this function grab task from called function via global service, but register itself to awaiter, and return their own task - all just like current behaviour for async functions (except estabilishing service to acuire task)

For cross assembly compatibility, universal function can be marked with attribute (like SyncUniversalAttribute), so compilter will known if called function from library, will register internal task to service or not.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.