lingua icon indicating copy to clipboard operation
lingua copied to clipboard

Support specifying custom `Executor`

Open Marcono1234 opened this issue 2 years ago • 1 comments

Related to #119

Currently Lingua uses ForkJoinPool.commonPool() for model loading and language detection. However, maybe it would be useful to allow users to specify their own Executor, for example with LanguageDetectorBuilder.withExecutor(Executor) (the default could still be commonPool()). This would have the following advantages:

  • could customize worker thread count, or even run single-threaded, e.g. executor = r -> r.run()
  • could customize worker threads:
    • custom name to make performance monitoring easier
    • custom priority

It would not be possible anymore to use invokeAll then, but a helper function such as the following one might add the missing functionality:

private fun <E> executeTasks(tasks: List<Callable<E>>): List<E> {
    val futures = tasks.map { FutureTask(it) }
    futures.forEach(executor::execute)
    return futures.map(Future<E>::get)
}

(Note that I have not extensively checked how well this performs compared to invokeAll, and whether exception collection from the Futures could be improved. Probably this implementation is flawed because called would wait on get() call without participating in the work.) Alternatively CompletableFuture could be used; but then care must be taken to not use ForkJoinPool.commonPool() when its parallelism is 1, otherwise performance might be pretty bad due to JDK-8213115.

This would require some changes to the documentation which currently explicitly refers to ForkJoinPool.commonPool().

What do you think?

Marcono1234 avatar Aug 01 '22 10:08 Marcono1234

This sounds like a good idea. I will implement this for the next release.

pemistahl avatar Oct 24 '22 07:10 pemistahl