Как стать автором
Обновить

Многоагентная система для параллельного программирования (Java)

Время на прочтение 4 мин
Количество просмотров 7.1K

Агентно-ориентированное программирование





Тема дипломной работы в университете была «Многоагентные системы для обработки баз знаний». Подключение многоагентной системы Jade к базе знаний Protege не составило труда и диплом готов. Теперь можно моделировать абстрактные учебные задачи, рои агентов, и так далее и тому подобное. Но возник вопрос, а как применить на деле полученные знания? Случай завершить НИОКР подвернулся при работе над системой «умный дом». Потребовалось небольшое многопоточное приложение для передачи данных от «умного дома» стороннему разработчику веб-интерфейсов. Вот прекрасная возможность применить Агентно-ориентированное программирование. В результате была успешно создана многоагентная система для параллельного программирования.



Ключевые классы многоагентной системы



Для наилучшего понимания основную идею можно сформулировать следующим образом: ментальная модель системы — это агенты работающие в потоках. Идея проста — потоки это сложно, поэтому отделим их от прикладных алгоритмов.

Классы Agency и Agent


Класс Agency спроектирован потокобезопасным. А в классе Agent стоит обратить внимание на паттерн типа «универсальный инструментарий»
package socialIntelligencejava;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentSkipListMap;

/** агенты через этот класс найдут друг друга (даже если они в разных потоках) */
public class Agency {

    String name = "defaultAgencyName";

    /** справочник агентов */
    public ConcurrentSkipListMap<String, Agent> agentReference = new ConcurrentSkipListMap<>();

    /** общая очередь заданий */
    public ConcurrentLinkedQueue<Agent> missions = new ConcurrentLinkedQueue<>();   

    /** потокобезопасное добавление задания в очередь */
    public synchronized void addMission(Agent agent) {        
         {
            this.missions.add(agent);
            notify();
        }
    }
    
    /** потокобезопасное извлечение задания из очереди */
    public synchronized Agent nextMission() throws InterruptedException {
         {
            while (missions.isEmpty()) {
                wait();
            }
        }
        return missions.poll();
    }
}

/** базовый класс для агентов */
public abstract class AbstractAgent {
    
    public String codeName = "DefaultAgent";    
    
    public abstract void go();
    
    /** ссылка на организацию агента */
    public Agency agency = null; 
}

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentSkipListMap;

/** агент */
public class Agent extends AbstractAgent {

    public Agent(Agency agency, String codeName, String task) {       
        this.codeName = codeName;
        this.agency = agency;
        this.agency.agentReference.put(codeName, this);
        this.mission = new Mission();
        this.mission.task = task;
    }   
        
    /**  здесь можно хранить все: задачи агента, результаты работы агента, инструменты агента (паттерн инструментарий) ... */
    public ConcurrentSkipListMap<String, Object> tools = new ConcurrentSkipListMap<>();

    /** мессенджер агента */
    public ConcurrentLinkedQueue<Message> messages = new ConcurrentLinkedQueue<>();

    public Message readMessage() { return messages.poll(); }
    public void addMessage(Message message) { messages.offer(message); }

    /** синхронное чтение: ожидание блокирует весь поток */
    public synchronized Message readMsgWait() {
        if (messages.isEmpty()) {
            try {
                wait();
            } catch (InterruptedException e) {}
        }
        return messages.poll();
    }

    /** синхронное уведомление: разблокировка потока */
    public synchronized void addMsgNotify(Message message) {
        messages.offer(message);
        notify();
    }   
    
    public String getInstruction() { return (String) this.tools.get("instruction"); }
    public void setInstruction(String instruction) { this.tools.put("instruction", instruction); }    
    
    public Mission mission;
    
    @Override
    public void go() {
        this.mission.accept(this);
    }
}


Класс ThreadAgent



В этом классе-потоке запускаются сценарии, внутри которых и работают агенты. Они могут общаться друг с другом даже если они работают в разных потоках. Схожее решение предоставляет нам MPI. Кстати, в один поток можно отправить на работу сразу несколько агентов.

package socialIntelligencejava;

/** базовый класс для потоков */
public abstract class AbstractThread extends Thread {

    public String name = "default";

    /** ссылка на группу в которою включен поток */
    public ThreadPool pool = null;

    /** отцепиться от группы  */
    public void unlink() {
        if (this.pool.threads.containsKey(this.name)) {
            this.pool.threads.remove(this.name);
        }
    }
}

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * один из типов потоков: агенты с заданиями из общей очереди
 */
public class ThreadAgent extends AbstractThread {

    public Agency agency = null;

    @Override
    public void run() {

        Agent agent = null;

        while (true) {
            System.out.println(name + " поток запущен.");
            try {
                agent = agency.nextMission();
                System.out.println(this.name + ": агент " + agent.codeName);
            } catch (InterruptedException ex) {
                Logger.getLogger(ThreadAgent.class.getName()).log(Level.SEVERE, null, ex);
            }
            
            //запуск сценария
            try {
                agent.go();
            } catch (IllegalArgumentException ex) {
                Logger.getLogger(ThreadAgent.class.getName()).log(Level.SEVERE, null, ex);
            }

            //уничтожение потока
            if (agent.getInstruction().equals("kill")) {
                this.unlink();
                System.out.println("Thread " + this.name + " killed");
                break;
            }
        }
    }
}


Исходный код системы



По ссылке в конце статьи можно получить исходный код системы. Сам код представляет собой каркас (FrameWork) который можно расширять, создавая инструменты для агентов, проектируя новые потоки. Для управления потоками реализован класс ThreadPool.java. Использованы lock-free структуры данных для безопасной работы потоков. Также присутствуют тестовые примеры работы системы. Исходя из опыта скажу, что удобно работать со сторонним кодом. Загружаем его в сценарий и отправляем в поток, а агент по ходу выполнения стороннего кода вносит в него свои коррективы. Скачиваем, пишем параллельные программы и забываем о прокрустовом ложе шаблона producer-consumer.
Можете подключать к агентам свой искусственный интеллект: базы знаний, экспертные системы, нейросети…

Исходный код системы Social-Intelligence: gitflic.ru/project/neutrino/agency.git
Теги:
Хабы:
+3
Комментарии 3
Комментарии Комментарии 3

Публикации

Истории

Работа

Java разработчик
356 вакансий

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн