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

In trio.to_thread.run, give a better error message if passed a sync function #1244

Closed
kantrol opened this issue Oct 10, 2019 · 3 comments · Fixed by #1513
Closed

In trio.to_thread.run, give a better error message if passed a sync function #1244

kantrol opened this issue Oct 10, 2019 · 3 comments · Fixed by #1513

Comments

@kantrol
Copy link

kantrol commented Oct 10, 2019

I needed to decouple sender and receiver and initialized the channel with max_buffer_size>0. Lost elements are accepted when buffer is full, but sendchannel.send_nowait throws

TypeError: object NoneType can't be used in 'await' expression

I had expected that the channel could be filled up to max_buffer_size.
For demonstration I made minor changes to the threaded channel example:

import trio

def thread_fn(receive_from_trio, send_to_trio):
    while True:
        # Since we're in a thread, we can't call methods on Trio
        # objects directly -- so we use trio.from_thread to call them.
        try:
            request = trio.from_thread.run(receive_from_trio.receive)
            response = request + 1
            trio.from_thread.run(send_to_trio.send_nowait, response)
        except trio.WouldBlock:
            print('would block')
        except trio.EndOfChannel:
            trio.from_thread.run(send_to_trio.aclose)
            return

async def main():
    send_to_thread, receive_from_trio = trio.open_memory_channel(1)
    send_to_trio, receive_from_thread = trio.open_memory_channel(1)

    async with trio.open_nursery() as nursery:
        # In a background thread, run:
        #   thread_fn(portal, receive_from_trio, send_to_trio)
        nursery.start_soon(
            trio.to_thread.run_sync, thread_fn, receive_from_trio, send_to_trio
        )

        # prints "1"
        await send_to_thread.send(0)
        
        # simulate a slow starting receiver
        await trio.sleep(2)
        print(await receive_from_thread.receive())       

        # prints "2"
        await send_to_thread.send(1)
        print(await receive_from_thread.receive())

        # When we close the channel, it signals the thread to exit.
        await send_to_thread.aclose()

        # When we exit the nursery, it waits for the background thread to
        # exit.


trio.run(main)
@njsmith
Copy link
Member

njsmith commented Oct 10, 2019

Ah, that's a bit tricky. The issue is that send is an async function, but send_nowait is a sync function, so you call them differently.

Normally, the difference is that you use await on async functions, and don't on sync functions, and that's the underlying issue here.

But, it's a bit obfuscated, because here you're not calling the function directly – instead you're passing it to trio.from_thread, and it's doing the actual calling.

So the issue here is that trio.from_thread.run is used for async functions. If you want to call a sync function from a thread, you have to switch to using trio.from_thread.run_sync instead.

So that should solve your immediate problem. In the longer run – maybe we can give a more helpful error message here?

@kantrol
Copy link
Author

kantrol commented Oct 10, 2019

I expected something in that area, but thought that trio.from_thread would handle this internally. A helpful error message should cover this case but in the meantime a note in the docs could be sufficient.
Thanks.

@njsmith njsmith changed the title sendchannel.send_nowait throws TypeError: object NoneType can't be used in 'await' expression In trio.to_thread.run, give a better error message if passed a sync function Nov 4, 2019
@guilledk
Copy link

guilledk commented May 12, 2020

Hey guys just tried to give it a go, first time sending a PR to an open source project!
#1513

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants