Архитектура многопоточной модульной системы для .NET

Рейтинг: 3Ответов: 1Опубликовано: 25.11.2014

Итак, к примеру есть игра - симулятор футбола.
Есть глобальный для сессии игры объект, который включает в себя список футбольных клубов, игроков в них и т.п. Данных тысячи и тысячи.

Корневой элемент игры примерно такой:

public async void Run(ISession session)
    {
        while (true)
        {
            dynamic result = await session.Go();

            if (result.ReadyToAction)
            {
                _gameControlEvent.WaitOne();
            }
        }
    }

Т.е. происходит обработка каких-то глобальных данных в игре, и дальше пользователь на это как-либо реагирует, и продолжается то же самое. Бесконечно.
Дело в том, что игра делается постепенно, и функционал расширяется. Поэтому есть некоторые модули (модуль - класс, которому на вход подается объект с данными, и он обрабатывает их. Может как читать, так и писать в этот объект), который собственно и занимаются обработкой этой большой информации.

public async Task<GoResult> Go()
    {
        ...

        foreach (var module in _modules.OrderBy(x => x.Priority))
        {
            results.Add(module.ProcessGameData(GameData));
        }

        ..

        CurrentDate = CurrentDate.AddDays(1);
    }

GameData - это и есть наш глобальный объект.

Вопрос в том, как лучше организовать подобную архитектуру?

Допустим, сейчас есть модуль "Транферы", а в будущем я добавлю модуль, который должен подождать результат обработки некоторых других модулей. Например, добавлю модуль - Новости, а он должен дождаться результата выполнения модулей Трансферы, Продление контракта, и т.п. Т.е. как организовать такие зависимости между обработчиками.

Подразумевается, что каждый модуль может работать в отдельном потоке. Может быть, уже есть какие-либо структурированные алгоритмы, схожие с этим?

Все почему-то отвечают на типичные многопоточный вопросы. я не про это спрашиваю.

Жесткая структура не нужна. Нужно чтобы добавление модуля никак не меняло функционал системы. Т.е вы пишите модуль, добавляете зависимости и все само работает

class TransferModule{ 
    TransferModule(INewsModule newsModule){
    //модуль трансфера отработает только после того, как завершиться выполнения модуля News     
    }

}

Ответы

▲ 1

Я думаю вам для решения данной задачи будет достаточно прибегнуть к Task.ContinueWith

Вот набросок.

    public interface IGlobalData
    {

    }

    public class GlobalData : IGlobalData
    {

    }

    public interface IModule
    {
        IGlobalData ProcessGameData(IGlobalData globalData);
    }

    public class Module : IModule
    {
        public virtual IGlobalData ProcessGameData(IGlobalData globalData)
        {
            return globalData;
        }
    }

    public class News : Module
    {
        public override IGlobalData ProcessGameData(IGlobalData globalData)
        {
            Console.WriteLine("News");
            return base.ProcessGameData(globalData);
        }
    }

    public class Transfers : Module
    {
        public override IGlobalData ProcessGameData(IGlobalData globalData)
        {
            Console.WriteLine("Transfers");
            return base.ProcessGameData(globalData);
        }
    }

    public class AnotherModule : Module
    {
        public override IGlobalData ProcessGameData(IGlobalData globalData)
        {
            Console.WriteLine("AnotherModule");
            return base.ProcessGameData(globalData);
        }
    }

    class Continuations
    {
        static void Main()
        {
            var globalData = new GlobalData();

            var rootTask = new Task<IGlobalData>(() => new Transfers().ProcessGameData(globalData));
            var newsTask = rootTask.ContinueWith(t => new News().ProcessGameData(t.Result));
            var anptherTask = newsTask.ContinueWith(t => new AnotherModule().ProcessGameData(t.Result));

            rootTask.Start();
            Console.ReadKey();
        }
    }