BusinessDuck/async-genetic

Running fitness functions one after the other.

arthurwolf opened this issue · 5 comments

Hey.

I'm using async-genetic (great project btw), but I'm running into trouble.
I have this evaluation function that takes a few seconds under normal circumstances.
But when I use it inside of async-genetic, it starts taking many minutes to do the exact same thing.
As far as I can tell, this is due to async-genetic attempting to run all of the evaluation functions at the same time (async/await stuff) instead of one after the other.
Is there any way to make sure it waits for one evaluation/fitness function to return before running the next one?

Thanks!

Hi! Async mean all functions call in one time, that's great for worker threads architecture.

That's mean my answer is no, not possible to do that from out the box.

But good news for you, it can be customised. You need to create scheduler and queue inside of your fitness function. Just create array with tasks (fitnessTask) and when genetic library calls fitness, do nothing, just add task to queue and return the promise, that should be resolved when task in queue has been resolved. And start solving tasks one by one on your side. That's will works as you need.

FWIW, here is what GPT4 recommended when presented with our conversation:

import { GeneticAlgorithm } from 'async-genetic';

// Your async score function
async function score(ids: number[]): Promise<number> {
  // Evaluate and return the score of the given list of IDs
  // ...
}

class FitnessQueue {
  private queue: (() => Promise<void>)[] = [];
  private isRunning = false;

  async add(task: () => Promise<number>): Promise<number> {
    return new Promise<number>(async (resolve) => {
      this.queue.push(async () => {
        const result = await task();
        resolve(result);
      });

      if (!this.isRunning) {
        this.isRunning = true;
        while (this.queue.length > 0) {
          const currentTask = this.queue.shift();
          if (currentTask) {
            await currentTask();
          }
        }
        this.isRunning = false;
      }
    });
  }
}

const fitnessQueue = new FitnessQueue();

async function fitnessFunction(ids: number[]): Promise<number> {
  return await fitnessQueue.add(() => score(ids));
}

const ga = new GeneticAlgorithm({
  // ... (other configuration options)
  fitness: fitnessFunction,
});

(async () => {
  // Run the genetic algorithm and get the result
  // ...
})();

edit: it works.

note, now that I have it working correctly running them one at a time, I'd like to get it to run 8 in parralel, but I'm similarly stuck, I'm not sure how to do that.
if you designed the library to enable multi-threading, shouldn't it have some kind of option to just handle it out of the box?

Here is an example #5