-
InfluxDB
Power Real-Time Data Analytics at Scale. Get real-time insights from all types of time series data with InfluxDB. Ingest, query, and analyze billions of data points in real-time with unbounded cardinality.
-
SaaSHub
SaaSHub - Software Alternatives and Reviews. SaaSHub helps you find the best software and product alternatives
Here are all my solutions.
1 - partial is defining a new function that ignores the type hints from func, and would introduce boxing. It also can introduce a performance hit for (remaining) argument arities > 3, since it automatically invokes a varargs variant instead of providing a concrete arity. With the varargs version, in profiling you may see RestFn showing up on hot paths, which is the varargs implementation having to munge seqs every invocation instead of being able to use concrete args matching discrete arities. Depending on the frequency of invocation this may impact performance.
3 - Similar to 2, the savings of mutably building the collection have to outweigh the cost of persisting it. Or if you are using the transient as a mutable container (e.g. held by an item) for limited random access and writes (as opposed to say a mutable arraylist or hashmap or hashset), performance should still be substantially better for writes over the persistent counterparts. The most gains come from building up large collections, using transients to mutably collect values and then persist at the end. Similar idea (but more general) in ham-fisted.
Regarding hashing, custom hash functions even for records (if all fields are longs for example) can help substantially if you are hashing points some notes here. Even then, depending on what you are doing, you may be better off using a primitive numeric representation and a dense collection (e.g. a primitive array) since the mechanical sympathy may be substantial. It is also possible to do well using nested maps (particularly for memoization) when the pieces of a compound key are already trivially hashed. E.g. clojure.core/memoize just defines a varargs wrapper around a function and caches the sequence of args in a map. For earlier reasons, this is a poor strategy for many functions and performance can be substantially improved (e.g. for a 1 or 2 arg function of numbers or keys or strings even) if we defined fixed arity paths that store keys in nested maps instead of hashing complex collections.
IIRC clojure.core/merge is another needlessly slow implementation that gets used a lot. If you are leveraging that on hot paths you will probably see some benefit in writing your own variant or copying one (or adding a dep) from a lib that is faster. There are some explorations of these ideas in clj-fast with some early results and trends and plenty of interesting discussions in the issues.