-
Notifications
You must be signed in to change notification settings - Fork 154
[WIP] library(async) providing async/await semantics #3041
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
base: master
Are you sure you want to change the base?
Conversation
src/lib/async.pl
Outdated
:- use_module(library(time)). | ||
main :- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also here and the following cases: I have made good experiences with the name run/0
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
First of all, this looks awesome and impressive, thank you so much for working on what appears to quickly become an invaluable contribution! Second, could you please explain what this exactly is to someone who is not familiar with the used terminology and computational model? I read the documentation, for example this: %% async_event_loop(+Goals) % Goals is a list of goals that may be asyncronous, meaning that that `await/1` % will unify within this context and fail otherwise. What is "may be asyncronous" (i.e., under what conditions are they asyncronous), and even more urgently: What exactly is "asyncronous"? Only from "meaning that that The documentation states "asyncronous but not concurrent or parallel", from which I also could not deduce it, but I see that there must be an important difference, what exactly is it? (And is "concurrent" synonymous with "parallel"?) "Coroutine" also occurs in the documentation, exactly once, is that synonymous with any of the other concepts? The reason why this looks so immensely impressive to me is that at least from the documentation and examples, I get the impression that this may be a way to implement for example an HTTP server that handles different clients, in such a way that a single hanging client does not block other clients, is that the case? If so, then this may vastly reduce the need for multiple threads (#546), where you @matt2xu also already mentioned asynchronous IO in #546 (comment). |
The usual meaning is:
Some key takeaways:
I feel that maybe these words are not being used exactly that that in the documentation mentioned.
This is an example in which you need parallelism, not just concurrency, at least if you use blocking operations. If some task blocks and you only have cooperative concurrency, then the whole program, including all tasks, will freeze because it has to wait to be unblocked before it can continue working on anything. You can also use non-blocking operations and do this with cooperative concurrency just fine, which is why Javascript is a great language for servers even though it's single threaded, but that is much trickier to get right. Some resources about this: |
This is a primary motivating use case -- the only thing we need now is a form of nonblocking I/O, preferably a "sliceable" I/O. Meaning, rather than a timeout, we have a duration. So, Of course, OS-level threads would allow for true concurrency! So, no need for non-blocking I/O! |
@bakaq thank you for this, I was struggling with how to succinctly put this in the documentation, I should just copy/paste this in there! |
Yes, I failed to explain this properly. "may be asynchronous" means that goals run with This is effectively the same as a Python generator. This can also be achieved with However one major benefit of programming with So, the primary use case is probably for side effects, such as reading from and writing to streams. Otherwise the logical result would be the same in all cases as synchronous code, I believe -- this is a strong claim, but I can't figure out how to disprove it. You will notice than in the tests I needed to use mutation with the blackboard to prove that the code is async. I will consider what level of detail to include in the documentation. In general, are the documentation comments for Scryer meant to be a full tutorial? What level of experience is assumed? For instance, the |
I would say: You have complete freedom regarding shape and extent of the library documentation. Ideally, the combination of existing material (the text itself and external resources) makes clear what the point of the library is and how one can use it. For instance, the clpz documentation is quite comprehensive, but library(cont) assumes you have read the 2 papers. The interface of I think Another reason to keep the documentation minimal and even lacking could be to encourage discussion about an interface that warrants discussion because it is not yet finalized even though the library is already sufficiently useful to collect initial feedback. |
Looks like I have some
|
% the `Goal` will operate as a coroutine. Note that it is asyncronous | ||
% but NOT concurrent or parallel without invoking an external process. | ||
|
||
:- meta_predicate(await(+)). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be 0
? The goal takes no additional arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made the change and I believe this is correct, and I believe user code works with this change, but the test code is behaving strangely now. I am hesitant to jump to conclusions because I usually jump to the wrong conclusion, will need to investigate further when I have time.
Asynchronous Programming in Scryer Prolog
Motivated by a desire to use Scryer as the command and control center for coordinating multiple external processes, I managed to cobble together some async semantics that I think others will find useful, as they are fairly unobtrusive.
There are only two exposed predicates:
async_event_loop/1
andawait/1
. Goals called withasync_event_loop/1
can useawait/1
predicate to invoke asynchronous flow control.I think looking at the testing file provides best overall view of usage, but you can also see the discussions for more flavor.
Feedback welcome.
Edit: to WIP until I figure out the meta predicate declarations