2

I've been curious about Quasar and its light weight Fibers as a replacement for Threads. After consulting their API docs, I have not been able to figure out how to go about converting a typical ThreadPoolExecutor into a pool of Fibers.

int maxThreadPoolSize = 10;

ThreadPoolExecutor executor = new ThreadPoolExecutor(
        maxThreadPoolSize,
        maxThreadPoolSize,
        10, TimeUnit.MINUTES,
        new ArrayBlockingQueue<Runnable>(maxThreadPoolSize),
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.CallerRunsPolicy()
);

for (int i = 0; i < 100; i++) {
    executor.execute(new Runnable() {
        @Override
        public void run() {
            // run some code
        }
    });
}

The above code creates a pool with 10 threads, a queue in front of the pool that can hold 10 elements and a rejection policy (when queue is full) to have main thread execute a Runnable task itself. As the for loop creates 100 runnables, they will be executed 10 at a time in the pool, 10 queued up, and main thread picks up a Runnable itself until others are finished, after which main thread goes back to adding Runnables to executor.

How would you do this with Quasar's Fibers? Is it meant to be used as such in the first place?


EDIT: My original question was poorly phrased. Essentially I was trying to find a mechanism to limit how many Fibers can run concurrently. For example, do not launch more Fibers if there is already 200 Fibers running. If max number of Fibers are running, wait until one finishes before launching a new one.

4 Answers4

0

Fibers are very cheap so you shouldn't need pooling (and its async job-dispatching model) at all: just fire up a fiber and let it run regular sequential code every time you need a new sequential process to be run concurrently with others.

circlespainter
  • 836
  • 5
  • 8
  • 1
    I'm entertaining a Fiber pool, because with their introduction the bottleneck of my application may shift from # threads to memory/cpu. For example, if a pool of 100 threads is processing events from a queue, then the upper bound is set for memory/cpu. You can never have more than 100 events being processed concurrently. When switching to fibers, I'd like to be able to enforce a similar upper bound. Some type of mechanism to rate limit the server and never launch more than 2000 fibers. – Vlad Poskatcheev Oct 10 '16 at 21:12
  • 1
    I realized my initial terminology is poor and misleading. A pool of fibers doesn't make sense (since it's so cheap to launch them). I'm after an existing (to avoid re-inventing the wheel) mechanism to rate limit my server app to never launch more than X number of fibers concurrently. – Vlad Poskatcheev Oct 10 '16 at 21:29
0

Each fiber scheduled by a FiberScheduler, when you create a Fiber without scheduler, a FiberForkJoinScheduler will be created and assigned to this fiber.

In short, if you want to manage your fibers in a thread pool, use FiberExecutorScheduler: Quasar's document about scheduling fibers
Your code could be like this

    int maxThreadPoolSize = 10;
    ThreadPoolExecutor executor = new ThreadPoolExecutor(
            maxThreadPoolSize,
            maxThreadPoolSize,
            10, TimeUnit.MINUTES,
            new ArrayBlockingQueue<Runnable>(maxThreadPoolSize),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.CallerRunsPolicy()
    );

    FiberExecutorScheduler scheduler = new FiberExecutorScheduler("FibersInAPool", executor);
    for (int i = 0; i < 100; i++) {
        Fiber fiber = new Fiber<Void>(scheduler
                , new SuspendableCallable<Void>() {
            @Override
            public Void run() throws SuspendExecution, InterruptedException {
                // run some code
                return null;
            }
        });
        fiber.start();
    }
tiboo
  • 8,213
  • 6
  • 33
  • 43
  • I might be missing something, but this doesn't seem to address the problem. Namely how to implement a mechanism to limit how many Fibers can run concurrently. Above code utilizes a ThreadPoolExecutor which seems puzzling, because that's exactly what is trying to be replaced and avoided. The idea is to get away from using threads as much as possible and use Fibers instead. – Vlad Poskatcheev Dec 01 '18 at 00:34
  • afaik, quasar has monitor in scheduler (it has protected modifier), have you tried extending schedulers to access their monitors? https://github.com/puniverse/quasar/blob/master/quasar-core/src/main/java/co/paralleluniverse/fibers/MetricsFibersMonitor.java – tiboo Dec 03 '18 at 10:27
-1

java.util.concurrent.Semaphore ended up working well in my particular setup.

General gist of my solution:

  • create Semaphore with desired max number of permits (aka max concurrent Fibers)
  • main thread is in charge of picking up tasks to process from a queue
  • main thread calls semaphore.acquire():
    • if a permit is available, then launch new Fiber to process task
    • if all permits are taken, then semaphore will block main thread and wait until a permit becomes available
  • once Fiber is launched, main thread repeats its logic. Picks up a new task from queue and attempts to launch a new Fiber.

Bonus: standard Java's Semaphore is fixed and number of permits can not be dynamically adjusted. To make it dynamic this link came in handy: http://blog.teamlazerbeez.com/2009/04/20/javas-semaphore-resizing/

-2

we just did a pre-release of kilim 2.0. it provides a fiber and actor implementation (similar to quasar) and is backed by ThreadPoolExecutor

the most efficient way to limit the number of concurrent tasks would be to have one task serve as a controller and listen to a mailbox (i think quasar calls these channels) and maintain a count of running tasks. when each task finishes, message the mailbox

generally, it doesn't make sense to use more threads than there are cores

nqzero
  • 125
  • 1
  • 7