Skip to content

Latest commit

 

History

History
52 lines (29 loc) · 2.39 KB

File metadata and controls

52 lines (29 loc) · 2.39 KB

invisibles - overview

transparent remote method invocation. same object, same usage, different location.

the bet

you have an object. you want to move it to another process, another node. the code that uses it doesn't change. not about scaling or load balancing - about transparent relocation.

# local
result = view.get(slot_key)

# remote - identical
result = proxy.get(slot_key)

the caller can't tell local from remote. that's the whole point.

execution model

the proxy doesn't decide how to execute. it just forwards. the server side knows how to run the object based on how it was set up.

three executor modes, chosen by the user based on what their object actually is:

single-threaded - one object instance, not thread-safe, calls serialize. simplest case. good default.

threaded - thread-safe object, thread pool executor. concurrent sync calls from multiple clients.

async - object has async def methods, server runs an asyncio event loop. native coroutine execution. callers already write await obj.method() locally, same thing remotely.

the user picks the executor because they know their object. the framework doesn't guess.

these are 3 distinct modes. async and threaded executors are not mixed up. if you have 2 clients that want to talk same instance that has async methods, then all methods will be serialized. there is no run in executor magic for sycn calls because it might have unexpected results (dirty reads/writes) for users.

sync objects

regular def methods. caller writes result = obj.method(), expects to block. move it remote - result = proxy.method(). still blocks, still works. 1:1.

async objects

async def methods. caller writes result = await obj.method(). move it remote - result = await proxy.method(). server runs the coroutine natively on its event loop. 1:1.

no hybrid magic

the proxy doesn't detect caller context and switch behavior. that would break transparency - a local sync method doesn't magically become awaitable just because you call it from async code.

sync objects stay sync. async objects stay async. the execution model is a property of the object, not the caller.

industry example: Ray

Ray actors follow the same principle. actors are single-threaded by default (calls serialize). you opt into max_concurrency or declare async actors explicitly. the user declares the concurrency model, the framework respects it.