0

I found that we can create our own implementation of Task that can work with async and await. I know it would be bad Idea to create a custom implementation. But I want to know what things needs to be kept in mind while implementing MyTask and MyTaskAwaiter. I am looking for issues related to multithreading and deadlock.


//Example uses
public class MyApplicationClass
{
    private MyTask GetResult()
    {
        return new MyTask();
    }

    public async Task MyExposedMethod()
    {
        //Here I can await on my custom task implementation. 
        await GetResult();
    }
}

// My Custom Task. Instead of Task I will use MyTask
public struct MyTask
{
    public MyTaskAwaiter GetAwaiter()
    {
        return new MyTaskAwaiter();
    }
}

public struct MyTaskAwaiter : INotifyCompletion
{
    public bool IsCompleted
    {
        get
        {
            throw new NotImplementedException();
        }
    }

    public void GetResult()
    {
        throw new NotImplementedException();
    }

    public void OnCompleted(Action continuation)
    {
        throw new NotImplementedException();
    }
}
Arjun Vachhani
  • 1,761
  • 3
  • 21
  • 44
  • 6
    What problem do you want to solve? – Hans Kesting Jul 09 '23 at 08:38
  • I am exploring this approach. I may use it in low latency system. My goal is to avoid creating millions of `TaskCompletionSource` and `Task` objects each second. – Arjun Vachhani Jul 09 '23 at 08:45
  • 1
    `Task` is a structure in release configuration, you can also potentially decrease you latency by decreasing number of allocations in heap by using ValueTask with structures as result values. I would rather research some blog posts of Steven Toub, Stephen Cleary, and dive deeper in code before doing any custom implementations. Performance is a such subtle thing, you know. – Ryan Jul 09 '23 at 08:53
  • I know we can use ValueTask. In my case all the time task will complete asynchronously. So I dont see any benefit of ValueTask – Arjun Vachhani Jul 09 '23 at 08:57
  • ​`ValueTask`s can be used efficiently even when the completion is asynchronous. Check out the [`IValueTaskSource`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.sources.ivaluetasksource-1) interface, or look at [this](https://stackoverflow.com/questions/73043374/how-to-pause-resume-an-asynchronous-worker-without-incurring-memory-allocation "How to Pause/Resume an asynchronous worker, without incurring memory allocation overhead?") question for ideas. – Theodor Zoulias Jul 10 '23 at 06:59
  • 2
    These days there's `PoolingAsyncValueTaskMethodBuilder`, too. – Stephen Cleary Jul 10 '23 at 13:41

1 Answers1

1

Creating a custom implementation of Task and TaskAwaiter is a difficult task. It involves handling many aspects of asynchronous programming, multithreading, and deadlocks.

If you do decide to create your own implementation, here are some important things to keep in mind:

  • Make sure your implementation handles threading and concurrency correctly. Tasks are typically executed on a thread pool, so you need to manage threads carefully to prevent problems.

  • Implement the necessary mechanisms to allow asynchronous execution of your custom task. This involves providing an awaiter and ensuring that the task can be awaited using the await keyword.

  • Handle exceptions correctly. Make sure that exceptions are propagated correctly to the caller and that any caught exceptions are handled or rethrown appropriately.

  • Prevent deadlocks. Avoid blocking calls and use synchronization primitives carefully to prevent deadlocks.

  • Consider adding support for cancellation. This allows consumers to cancel the execution of your custom task if needed.

  • Follow the Task-Based Asynchronous Pattern (TAP) guidelines. This ensures that your custom task is compatible with other async-await-based code.

  • Thoroughly test your custom task implementation. This will help you identify and resolve any potential issues.

It is important to remember that creating a custom implementation of Task and TaskAwaiter is a complex task. It is generally recommended to rely on the robust and well-tested asynchronous APIs provided by the .NET framework.

Markus Safar
  • 6,324
  • 5
  • 28
  • 44
Vivek Nuna
  • 25,472
  • 25
  • 109
  • 197
  • 2
    Your answer looks quite similar in structure and content, with what ChatGPT responds when asked the same question ([screenshot](https://prnt.sc/Rdk5oYjWJvyI)). – Theodor Zoulias Jul 09 '23 at 10:13
  • my answer is very different than the one in the screenshot. points might be matching because this is a very generic question and answer. I agree when We answer questions we read from other resources as well to learn more. – Vivek Nuna Jul 09 '23 at 10:18