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

Improve readability of documentation #141

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

A promise library & concurrency toolkit for Clojure and ClojureScript.

This library exposes a bunch of usefull syntactic abstractions that
will considerably simplify to work with promises (in a very similar
This library exposes a bunch of useful syntactic abstractions that
considerably simplify working with promises (in a very similar
way as you will do it in JS with async/await) and many helpers from
executors to concurrency patterns (bulkhead & CSP). With 0 runtime
external dependencies.
Expand Down Expand Up @@ -44,7 +44,7 @@ primitives on JS runtime.
## Contributing

If you miss something, feel free to open an issue for a discussion. If
there is a clear use case for the proposed enhacement, the PR will be
there is a clear use case for the proposed enhancement, the PR will be
more than welcome.

## Testing
Expand Down
14 changes: 7 additions & 7 deletions doc/bulkhead.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Bulkhead (concurrency limiter)

In general, the goal of the bulkhead pattern is to avoid faults in one part of a system to take the
In general, the bulkhead pattern prevents faults in one part of the system from taking the
entire system down. The bulkhead implementation in **promesa** limits the number of concurrent
calls.

This [SO answer][0] explains the concept very well.


So lets stat with an example:
So let's start with an example:

```clojure
(require '[promesa.exec.bulkhead :as pxb]
Expand All @@ -25,17 +25,17 @@ So lets stat with an example:
```

At first glance, this seems like an executor instance because it resembles the same API (aka
`px/submit! call).
`px/submit!` call).

When you submits a task to it, it does the following:
When you submit a task to it, it does the following:

- Checkes if concurrency limit is not reached, if not, proceed to execute the function in the
- Checks if concurrency limit is not reached, if not, proceed to execute the function in the
underlying executor.
- If concurrency limit is reached, it queues the execution until other tasks are finished.
- If queue limit is reached, the returned promise will be automatically rejected with an exception
indicating that queue limit reached.
indicating that queue limit was reached.

This allows control the concurrency and the queue size on access to some resource.
This allows you to control the concurrency and the queue size on access to some resource.


NOTES:
Expand Down
62 changes: 31 additions & 31 deletions doc/channels.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
# Channels (CSP pattern)

An implementation of channel abstraction and CSP patterns for Clojure and ClojureScript.
It's a [core.async][3] alternative implementation of channel abstraction that laverages
platform facilities for concurrency (no go macro transformations, laverages JDK19 Virtual
Threads on the JVM).
It's a [core.async][3] alternative implementation of channel abstraction that leverages
platform facilities for concurrency (no go macro transformations, leverages virtual threads on the JVM).

There are [Code Walkthrought][0] where you can learn the main API usage patterns. Also,
**NOTE**: Virtual threads are only available on JDK 21+ (or JDK 19 with experimental features enabled).

See the [Code Walkthrough][0] to learn the main API usage patterns. Also,
you can read the [core.async rationale][1] for better understanding the main ideas of the
CSP pattern.

**NOTE**: Although the main focus is the use in JVM, where is all the potential; the
**NOTE**: Although the main focus is the use in JVM, where all of the potential is, the
channel implementation is also available on CLJS. There are no go macros on CLJS, but all
the operators (including `alts`) can be used with alredy available promesa API and
syntactic abstractions (such that `promesa.core/loop` and `promesa.core/recur`). Read the
docstring for know if the operator/helper internally uses vthreads or not.
the operators (including `alts`) can be used with already available promesa API and
syntactic abstractions (such as `promesa.core/loop` and `promesa.core/recur`). Read the
docstring to know if the operator/helper internally uses vthreads or not.


## Differences with `core.async`
Expand All @@ -23,35 +24,34 @@ The main highlights and differences with [core.async][3] are:
- **There are no macro transformations**, the `go` macro is a convenient alias for
`p/vthread` (or `p/thread` when vthreads are not available); there are not limitation on
using blocking calls inside `go` macro neither many other inconveniences of core.async
go macro, mainly thanks to the JDK19 with preview enabled Virtual Threads. _They are
only available on JVM_.
go macro, mainly thanks to virtual threads. _They are only available on JVM_.
- **No callbacks**, functions returns promises or blocks; you can use the promise
composition API or thread blocking API, whatever you wants.
composition API or thread blocking API, whatever you want.
- **No take/put limits**; you can attach more than 1024 pending tasks to a channel.
- **Simplier mental model**, there are no differences between parking and blocking
- **Simpler mental model**, there are no differences between parking and blocking
operations.
- **Analogous performance**; in my own stress tests it has the same performance as
core.async.
- **First class errors** support on channels.

There are also some internal differences that you should know:

- The promesa implementation cancells immediatelly all pending puts when channel is closed
in contrast to core.async that leaves them operative until all puts are succeded.
- The promesa implementation takes a bit less grandular locking than core.async, but on
the end it should not have any effect on the final performance orq usability.
- Operators or channel helpers do not use vthreads internally so they can be used safelly
- The promesa implementation immediately cancels all pending puts when channel is closed
in contrast to core.async that leaves them operative until all puts are succeeded.
- The promesa implementation takes less of a granular locking approach than core.async, but
it should not have any effect on the final performance or usability.
- Operators or channel helpers do not use vthreads internally so they can be used safely
on CLJS or JVM without virtual threads.


## Getting Started

This documentation supposes you have a bit of knowledge of core.async API.
This documentation assumes you have a bit of knowledge of core.async API.


#### Working with channels API

Lets create a channel and put value in-to:
Let's create a channel and put a value in it:

```clojure
(require '[promesa.exec.csp :as sp])
Expand All @@ -68,7 +68,7 @@ Lets create a channel and put value in-to:
;; => true
```

Now, lets try to retrieve data from channel:
Now, let's try to retrieve data from channel:

```clojure
;; Using a blocking helper, analogous to clojure.core.async/<!!
Expand Down Expand Up @@ -117,7 +117,7 @@ But if you need a channel, there are `go-chan` macro. The `go` +

#### Multiple Operations

If you want perform multiple operations on the same or mutliple
If you want to perform multiple operations on the same or multiple
channels. In the same line as `clojure.core.async/alts!!`, this
library exposes the `promesa.exec.csp/alts!` macro that has the same
API:
Expand Down Expand Up @@ -174,9 +174,9 @@ and `mult*`.
;; go 2: :a
```

The `mult` constructor returns a muliplexer, and as it implements the channel API, you can
The `mult` constructor returns a multiplexer, and as it implements the channel API, you can
put values in directly. For the cases when you already have a channel that you want
multiplext, just use the `mult*`.
multiplex, just use the `mult*`.

The `mult*` works in the same way as `clojure.core.async/mult`. There are also `untap!`
function for removing the channel from the multiplexer.
Expand All @@ -186,31 +186,31 @@ Closed channels are automatically removed from the multiplexer.

#### Errors

On difference with `core.async`, promesa channels supports the notion of error. The errors
can happen externaly (a producer process that fails) or internally (happens on the
One difference with `core.async`, promesa channels supports the notion of error. The errors
can happen externally (a producer process that fails) or internally (happens on the
provided transducer).

For notify of a possible external exception cause, you should proceed to call close!
For notification of a possible external exception cause, you should proceed to call close!
function with the cause as second argument:

```clojure
(sp/close! ch (ex-info "error" {}))
```

If the exception is happened on the transducer, the channel will be closed with that
exception. This behavior can be overriden spcifying custom exception handler on the
exception. This behavior can be overridden specifying custom exception handler on the
channel constructor:

```clojure
(def ch (sp/chan :buf 1 :xf (map inc) :exh sp/throw-uncaught))
```

The `sp/throw-uncaught` function is a builtin exception handler that just uses the
platform mechanism to throw the exception to the uncaugh handler (the default behavior of
platform mechanism to throw the exception to the uncaught handler (the default behavior of
core.async). If no `:exh` parameter is provided the `sp/close-with-exception` will be
used. Only relevent if you provide transducer.
used. This is only relevant if you provide transducer.

An exception handler is just a function that accepts two arguments: he channel and the
An exception handler is just a function that accepts two arguments: the channel and the
exception instance.


Expand All @@ -229,6 +229,6 @@ executor on the channel constructor:
```


[0]: https://github.com/funcool/promesa/blob/master/doc/csp-walkthrought.clj
[0]: https://github.com/funcool/promesa/blob/master/doc/csp-walkthrough.clj
[1]: https://clojure.org/news/2013/06/28/clojure-clore-async-channels
[3]: https://github.com/clojure/core.async
File renamed without changes.
45 changes: 22 additions & 23 deletions doc/executors.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,26 @@

## Introduction

Additionally to the _promise_ abstraction, **promesa** library comes
with many helpers and factories for execution and scheduling of tasks
In addition to the _promise_ abstraction, **promesa** comes
with many helpers and factories for execution and scheduling tasks
for asynchronous execution.

Although this API works in the JS runtime and some of the function has
Although this API works in the JS runtime and some of the functionality has
general utility, the main target is the JVM platform.

## Async Tasks

Firstly, lets define **async task**: a function that is executed out
An **async task** is a function that is executed out
of current flow using a different thread. Here, **promesa** library
exposes mainly two functions:

- `promesa.exec/run!`: useful when you want run a function in a
different thread and you don't care abour the return value; it
returns a promise that will be fullfilled when the callback
- `promesa.exec/run!`: useful when you want to run a function in a
different thread and you don't care about the return value.
It returns a promise that will be fulfilled when the callback
terminates.
- `promesa.exec/submit!` useful when you want run a function in a
different thread and you need the return value; it returns a promise
that will be fullfilled with the return value of the function.
- `promesa.exec/submit!` useful when you want to run a function in a
different thread and you need the return value. It returns a promise
that will be fulfilled with the return value of the function.


Let see some examples:
Expand All @@ -41,13 +41,13 @@ Let see some examples:
;; => 1
```

The both functions optionally accepts as first argument an executor
instance that allows specify the executor where you want execute the
specified function. If no executor is provided, the default one is
used (binded on the `promesa.exec/*default-executor*` dynamic var).
Both functions optionally accept an executor instance as the first argument.
This executor is used to run the specified function.
If no executor is provided, the default one is
used (bound on the `promesa.exec/*default-executor*` dynamic var).

Also, in both cases, the returned promise is cancellable, so if for
some reason the function is still not execued, the cancellation will
some reason the function is still not executed, the cancellation will
prevent the execution. You can cancel a cancellable promise with
`p/cancel!` function.

Expand Down Expand Up @@ -112,12 +112,11 @@ Since v9.0.x there are new factories that uses the JDK>=19 preview API:
### `pmap` (experimental)

This is a simplified `clojure.core/pmap` analogous function that allows
execute a potentially computationally expensive or io bound functions
in parallell.
execution of a potentially computationally expensive or IO bound functions
in parallel.

It returns a lazy chunked seq (uses the clojure's default chunk size:
32) and the maximum parallelism is determined by the provided
executor.
It returns a lazy chunked seq (uses Clojure's default chunk size of 32)
and the maximum parallelism is determined by the provided executor.

Example:

Expand All @@ -144,16 +143,16 @@ Example:

### `with-executor` macro (experimental)

This allows run a scoped code with the `px/*default-executor*` binded
This allows running scoped code with the `px/*default-executor*` bound
to the provided executor. The provided executor can be a function for
lazy executor instantiation.

It optionally accepts metadata on the executor part for indicate:
It optionally accepts metadata on the executor:

- `^:shutdown`: shutdown the pool before return
- `^:interrupt`: shutdown and interrupt before return

There an example on how you can customize the executor for **pmap**:
Here is an example of customizing the executor for **pmap**:

```clojure
(time
Expand Down
Loading