Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Is *vm.Program thread-safe? Can multiple threads access this for expr.Run(..)? #707

Answered by antonmedv
rchougule asked this question in Q&A
Discussion options

Hello,

Apologies if I missed this somewhere in the documentation.

We have a use case where we'd want to compile and keep the rules instead of compiling always before the execution. Image a map which stores a RULE_NAME to *vm.Program which we get upon expr.Compile(..).

Question being,

  1. Can multiple goroutines/threads use this compiled expression, i.e. *vm.Program concurrently? Multiple goroutines/threads will call expr.Run with the same *vm.Program with different env.

I found this old discussion, though, couldn't confirm from the same.

Thanks,
Rohan Chougule

You must be logged in to vote

Expr supports concurrent execution, but there are key differences in how its components handle concurrency. Here's what you need to know:

Thread-Safe: *program.Program

  • Compiled programs are thread-safe and read-only. You can safely reuse a compiled *program.Program across multiple goroutines.
  • Example:
program, err := expr.Compile(`X + Y`)
if err != nil {
    panic(err)
}

// Safe to run in multiple goroutines
go expr.Run(program, Env{X: 1, Y: 2})
go expr.Run(program, Env{X: 3, Y: 4})

Not Thread-Safe: *vm.VM

  • VMs are not thread-safe. Each goroutine should create its own *vm.VM instance.
  • You can manually create a pool of vm machines with *vm.VM.
  • Each expr.Run() call creates a new VM.

Bes…

Replies: 1 comment · 3 replies

Comment options

Expr supports concurrent execution, but there are key differences in how its components handle concurrency. Here's what you need to know:

Thread-Safe: *program.Program

  • Compiled programs are thread-safe and read-only. You can safely reuse a compiled *program.Program across multiple goroutines.
  • Example:
program, err := expr.Compile(`X + Y`)
if err != nil {
    panic(err)
}

// Safe to run in multiple goroutines
go expr.Run(program, Env{X: 1, Y: 2})
go expr.Run(program, Env{X: 3, Y: 4})

Not Thread-Safe: *vm.VM

  • VMs are not thread-safe. Each goroutine should create its own *vm.VM instance.
  • You can manually create a pool of vm machines with *vm.VM.
  • Each expr.Run() call creates a new VM.

Best Practices

  1. Compile once, run many times: Reuse compiled programs to save on performance.
  2. Use one VM per goroutine: Create a new VM for each concurrent execution to avoid conflicts.

In short: programs are reusable across threads, but VMs need to be per goroutine. Keep these in mind to safely and efficiently use Expr in concurrent environments.

You must be logged in to vote
3 replies
@rchougule
Comment options

@antonmedv Really appreciate the prompt and comprehensive responses across the posts I have added. Thanks!

@rchougule
Comment options

Though, a doubt around the *vm.VM,

  • Do we need to create a pool of vm machines when we have hundreds of Rules getting executed every second? or can we rely on expr.Run(..) for every execution? Is there any performance diff expected?
@antonmedv
Comment options

can we rely on expr.Run(..) for every execution?

Yes.

Is there any performance diff expected?

It depends on expressions and environments. The best way is to benchmark for your specific use case.

As a starting point, expr.Run() should totally fine. Precompile your expressions, define custom functions using expr.Function() and it will be enough.

Answer selected by rchougule
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
🙏
Q&A
Labels
None yet
2 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.