Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] Coroutine Support in Mojo #3906

Open
1 task done
f0cii opened this issue Dec 22, 2024 · 3 comments
Open
1 task done

[Feature Request] Coroutine Support in Mojo #3906

f0cii opened this issue Dec 22, 2024 · 3 comments
Labels
enhancement New feature or request mojo-repo Tag all issues with this label

Comments

@f0cii
Copy link

f0cii commented Dec 22, 2024

Review Mojo's priorities

What is your request?

I would like to propose the addition of coroutine support in the Mojo programming language. I believe that integrating coroutine functionality would significantly enhance the language's capabilities, particularly for asynchronous programming and concurrent task management.

What is your motivation for this change?

Coroutines allow for writing asynchronous code in a more sequential and readable manner. They enable developers to pause and resume functions, making it easier to manage tasks that involve waiting for I/O operations or other time-consuming processes without blocking the main execution thread.

Any other details?

To illustrate the potential of coroutine support, I have implemented a sample code that utilizes the PhotonLibOS library, which provides coroutine capabilities. Below is a simplified version of the code:

from sys._build import is_debug_build
from collections import Dict
from os import getenv
from testing import assert_equal
from memory import UnsafePointer, stack_allocation
from atxs_classic import *


fn init_photon() raises -> None:
    var options = PhotonOptions()
    var ret = photon_init(INIT_EVENT_EPOLL, INIT_IO_NONE, options)
    assert_equal(ret, 0)


fn fini_photon() raises -> None:
    photon_fini()


struct TaskEntryRequest:
    var a: Int
    var b: Int

    fn __init__(out self, a: Int, b: Int):
        self.a = a
        self.b = b

    fn __del__(owned self):
        print("del")

    fn print(self):
        print("a: " + str(self.a) + " b: " + str(self.b))


struct TaskEntryArg[T: AnyType]:
    var _data: UnsafePointer[T]

    fn __init__(out self, arg: c_void_ptr):
        self._data = arg.bitcast[T]()

    fn __del__(owned self):
        self._data.destroy_pointee()
        self._data.free()

    fn data(self) -> UnsafePointer[T]:
        return self._data


fn task_entry(arg: c_void_ptr) raises -> c_void_ptr:
    print("task_entry: " + str(arg))

    var a = TaskEntryArg[TaskEntryRequest](arg)
    print("a: " + str(a.data()[].a))
    print("b: " + str(a.data()[].b))

    print("task_entry end")

    return c_void_ptr()


fn test_work_pool() raises -> None:
    var a_ptr = UnsafePointer[TaskEntryRequest].alloc(1)
    __get_address_as_uninit_lvalue(a_ptr.address) = TaskEntryRequest(100, 5)

    print("a: " + str(a_ptr[].a))
    print("b: " + str(a_ptr[].b))

    # var arg = c_void_ptr()
    var arg = a_ptr.bitcast[UInt8]()
    seq_photon_thread_create_and_migrate_to_work_pool(task_entry, arg)
    print("test_work_pool done")


fn run_forever():
    seq_photon_join_current_vcpu_into_workpool(seq_photon_work_pool())


fn main() raises:
    seq_set_log_output_level(ALOG_FATAL)
    init_log("DBG", "")
    init_photon()

    seq_init_photon_work_pool(1)

    print("start")

    test_work_pool()

    run_forever()

    fini_photon()

I believe that adding coroutine support to Mojo would not only improve the language's usability but also attract more developers looking for efficient ways to handle asynchronous programming. I look forward to your thoughts on this proposal and am happy to assist in any way to help implement this feature.

Thank you for considering this request!

@f0cii f0cii added enhancement New feature or request mojo-repo Tag all issues with this label labels Dec 22, 2024
@owenhilyard
Copy link
Contributor

Mojo already has very WIP support for coroutines and async/await, but there's a group of us arguing over how exactly they should be implemented since Mojo aims to use the state of the art and solve all of the problems as best we can, instead of rushing toward familiar solutions. I personally lean away from stackful coroutines (what Photon has) due to the cost of maintaining the stack. There's also discussion around whether we want a form of structured concurrency to help manage async cancellation and similar problems that show up in most languages with coroutines.

@f0cii
Copy link
Author

f0cii commented Dec 27, 2024

I recommend considering the thread-per-core model used in the Monoio library developed by ByteDance. This approach might provide valuable insights as the team continues to explore coroutine implementation. You can find more information about Monoio here: https://github.com/bytedance/monoio.

@owenhilyard
Copy link
Contributor

I recommend considering the thread-per-core model used in the Monoio library developed by ByteDance. This approach might provide valuable insights as the team continues to explore coroutine implementation. You can find more information about Monoio here: https://github.com/bytedance/monoio.

I am aware of this. However, my current design is likely going to bend everything towards the state of the art (io_uring, DPDK, SPDK, etc) and make less capable APIs eat the costs. The POSIX-style API has a lot of disadvantages and starts to eat large amounts of memory bandwidth at higher IO rates. Something which does a better job of encouraging zero-copy, such as an abstraction over io_uring provided buffers, should work better for most people even if the API looks foreign at first. kTLS is also something we want to support, since crypto-capable NICs are far more common than they used to be.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request mojo-repo Tag all issues with this label
Projects
None yet
Development

No branches or pull requests

2 participants