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

completion-at-point freezes emacs when REPL is busy #123

Open
sjkobayashi opened this issue Jun 7, 2023 · 11 comments
Open

completion-at-point freezes emacs when REPL is busy #123

sjkobayashi opened this issue Jun 7, 2023 · 11 comments
Labels
enhancement New feature or request

Comments

@sjkobayashi
Copy link

I often run functions that take a lot of time to evaluate (such as simulation and optimization) in Julia's REPL. When REPL is busy, emacs can hang up when company-mode automatically tries completion or if I manually invoke completion-at-point. I have to repeatedly press C-g to unfreeze emacs. I imagine this happens because completion relies on REPL? Is there a way to avoid this other than disabling company-mode?

@gcv
Copy link
Owner

gcv commented Jun 7, 2023

Yes, this happens because Snail just uses the REPL thread. This problem should go away once #104 is fixed, which I'm starting to think needs to be a priority improvement.

@gcv gcv added the enhancement New feature or request label Jun 7, 2023
@gcv
Copy link
Owner

gcv commented Aug 4, 2023

I just released a change which should fix #104 and make this problem go away (a88755d). It'll be in MELPA in a couple of hours. Could you please give it a try and let me know what you think?

@sjkobayashi
Copy link
Author

Thank you for looking into this! It seems like it works when no computation is involved, but it still hangs when there's computation.

For instance, completion pops up when running the following:

for i in 1:30
    println(i)
    sleep(1.0)
end

But it hangs when running something like the following:

using BenchmarkTools
@btime exp.(rand(100000));

@gcv
Copy link
Owner

gcv commented Aug 24, 2023

It probably happens because Snail uses Julia tasks internally to manage concurrency. I will look into converting to (native) threads. I didn't do this initially because I've run into problems with JULIA_NUM_THREADS before (being unexpectedly set to 1 and therefore not really doing any meaningful multithreading). Thank you for the information, I'll update this ticket when I have some time to work on it.

@sjkobayashi
Copy link
Author

I see. Did that happen even with --threads=auto argument?

@gcv
Copy link
Owner

gcv commented Aug 25, 2023

Oh wow. I didn't know about the auto option. Since it has been available since 1.7, it means I have not looked into this in a long time. :) Thanks for telling me about it!

I'll definitely look into converting Snail from tasks to threads, then. Not exactly sure how much work it'll take.

Do you think I should also make Snail default to using the auto thread count option as long as the user hasn't overridden it? Or should I just document that it's a recommended value for julia-snail-extra-args?

@sjkobayashi
Copy link
Author

Happy to help! It seems like the -t/--threads argument takes precedence before JULIA_NUM_THREADS, so it may be safer to just say that it's a recommended value. A bit unrelated, but you may find this upcoming feature on 1.10 interesting too: JuliaLang/julia#48600

@gcv
Copy link
Owner

gcv commented Aug 30, 2023

I have threads kind of working on this branch: https://github.com/gcv/julia-snail/tree/experimental-threads

It seems to avoid locking up, but it has another problem: task interruption stopped working (from #104 and a88755d). The trick I used to stop a task on the current thread (schedule(task, InterruptException(), error=true)) causes all kinds of nasty crashes when used on a different thread.

I'm not sure what to do about it. Interrupting computation seems pretty important, but I don't see a robust way to implement it with Julia's current multithreading primitives.

@sjkobayashi
Copy link
Author

This could change too many things, but is it possible to have another Julia process for code completion? I'm not quite familiar with how VS Code's Julia extension works, but it seems like it uses SymbolServer.jl to obtain info about packages without loading them.

@gcv
Copy link
Owner

gcv commented Sep 14, 2023

A two-process solution is out of scope for Snail, but it should be possible to combine it with existing LSP tooling. You can disable Snail's non-REPL features as documented on the wiki (someone asked about this before). Then enable LanguageServer.jl. Emacs 29 comes with Eglot pre-installed, or you can try lsp-mode.

For Snail, I think the right solution is to introduce strict separation between computational commands sent to Julia by Snail itself and those sent by the user. The former would go into the :interactive threadpool, while the latter would be scheduled as tasks on the regular threadpool (documentation: https://docs.julialang.org/en/v1/manual/multi-threading/#man-threadpools). That would keep task interruption working for user-initiated computation, and should keep responsiveness for code completion.

That requires changing the Snail wire protocol to support tagging commands as :system and :user, which is a decent amount of work.

@sjkobayashi
Copy link
Author

Thanks for the suggestion and explanation. I've been using task interruption and find it very useful, so I will look into the language server option for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants