Я думаю, вам понравится решение F # :-).
Для простоты примера я храню цену и временные метки в списке, содержащем кортежи (первый элемент - это задержка с последнего обновления, а второй - цена). Не должно быть слишком сложно превратить ваши входные данные в этот формат. Например:
let prices = [ (0, 10.0); (1000, 10.5); (500, 9.5); (2500, 8.5) ]
Теперь мы можем создать новое событие, которое будет использоваться для воспроизведения процесса. После его создания мы немедленно подключаем некоторый обработчик, который будет печатать обновления цен:
let evt = new Event<float>()
evt.Publish.Add(printfn "Price updated: %f")
Последний шаг - реализация воспроизведения - это можно сделать с помощью асинхронного рабочего процесса, который циклически перебирает значения, асинхронно ожидает указанное время и затем запускает событие:
async { for delay, price in prices do
do! Async.Sleep(delay)
evt.Trigger(price) }
|> Async.StartImmediate
Я запускаю рабочий процесс, используя StartImmediate
, что означает, что он будет работать в текущем потоке (ожидание асинхронно, поэтому он не блокирует поток). Хранение всего однопоточного делает его немного проще (например, вы можете безопасно получить доступ к элементам управления GUI).
РЕДАКТИРОВАТЬ Чтобы обернуть функциональность в некоторый компонент, который может использоваться из других частей приложения, вы можете определить тип, подобный этому:
type ReplyDataStream(prices) =
let evt = new Event<float>()
member x.Reply() =
// Start the asynchronous workflow here
member x.PriceChanged =
evt.Publish
Пользователи могут затем создать экземпляр типа, прикрепить свои обработчики событий, используя stream.PriceChanged.Add(...)
, а затем начать воспроизведение записанных изменений, используя Reply()
.