Материал также доступен в виде видео:
Пока не забыл, хотелось бы обсудить такую актуальную для программистов во все времена тему, как сериализацию/десериализацию объектов.
Для тех кто в танке, программы выполняются на разных машинах и обмениваются данными по сети.
Типичный пример - вы заходите в интернет магазин, и пока забираете товар в корзину, содержимое хранится в памяти вашего компьютера в области программы браузера, а при оформлении заказа, отправляется на сервер.
Между тем, перед тем как передать объект, хранящийся в памяти на одном узле, его надо как-то закодировать, так как на том конце может быть другая программа, другой язык, да и вообще другой тип устройства, например, телефон а не компьютер.
И вот для промежуточного хранения файлов используют разные форматы.
Раньше был популярен xml, и с точки зрения инженеров он хорош, поддерживает серьезные механизмы для валидации, то есть проверки объектов.
Но в какой-то момент решили, что уж больно много в нем лишних символов передается, и надо что-то полегче.
Придумали Json, и этот формат с фигурными скобочками вместо тегов де-факто доминирует в передаче пакетов; многие таже используют его в качестве формата хранения данных. Например, noSql - БД mongoDB, и мало этого, она его использует еще и в качестве языка запросов, что как по мне, какая-то дичь, даже если забыть про остальные проблемы, которых я с ней нахлебался.
Но вернемся к нашим баранам.
Используя фреймворк Akka, который построен на очередях сообщений между Акторами (Actors) и поддерживает распределенную установку частей программы, я постоянно наблюдал сообщения о том, что я балбес, поскольку использую дефолтную Java сериализацию, что не рекомендуется.
Я, в свою очередь, считал, что балбесы те, кто выводит мне такие сообщения, поскольку между домашним сервером и клиентом у меня гигабитная сетка, и на объем мне наплевать; а что может быть быстрее, чем нативная сериализациия разработчиков Java - уж они-то знают, как лучше сохранять и загружать объекты.
В своем проекте я кэшировал данные, расчет которых занимал существенное время, и тоже использовал это механизм.
Тем не менее, в какой-то момент мне понадобилось прочитать те же данные из Питона (Python), который ясное дело, Java объекты не жрет.
Для сериализации я решил использовать библиотеку Spray, которая делала все практически из коробки, нужно было только указать DefaultJsonProtocol и задать несколько имплисит JsonFormat для вложенных кейс классов (классов для данных - в Scala).
Листинг привожу для изучения, замер времени чтения в первом блоке.
Интересный факт - стандартная сериализация валится на объектах типа Map (что при гуглении приводит нас к ошибке на распараллеливании вычислений Hadoop Spark, которая тоже не решена).
А вот Json валится, только если у вас число в качестве ключа Map.
И чтобы данные сериализовались Java writeObject, я переделал все на Sequence (для джавистов - List).
Каково же было мое удивление, когда размер файлов упал вдвое (!) с 66 до 30Мб, в время чтения сократилось в 40 (!) раз - с 66,3с до 1,5с.
Вот и думайте теперь, переходить ли на новые технологии, или сидеть на том, чему вас учили 20 лет назад.
Счет, как говориться на табло.
В связи с вышеизложенным, возможно, Spark можно существенно оптимизировать, отказавшись от этого вот тормозного вызова readObject.
val d = if (file.exists()) {
import java.io.FileInputStream
import java.io.ObjectInputStream
val log_start = System.currentTimeMillis()
// val is = new FileInputStream(file)
// val ois = new ObjectInputStream(is)
// val ret = ois.readObject.asInstanceOf[IndexedSeq[Seq[(Seq[MarketState], BigDecimal, BigDecimal,Long,Long)]]]
// ois.close()
// is.close()
val ret = Source.fromFile(file).mkString.parseJson.convertTo[IndexedSeq[Seq[(Seq[MarketState], BigDecimal, BigDecimal,Long,Long)]]]
logger.debug(s"---loaded ${(System.currentTimeMillis()-log_start)} ")
ret
} else {
val ret =
Await.result(Future.sequence(com.robot.data.DataProvider.GetData(tool,
sdf.parse(t1Str).getTime,
sdf.parse(t2Str).getTime,interval = 1000//60*60000
,smoothingInterval = 1000
,justChartPoints = false
,returnFuture = true)),Duration(100000,"s"))
// import java.io.FileOutputStream
// val fos = new FileOutputStream(file)
// val oo = new ObjectOutputStream(fos)
// oo.writeObject(ret)
// oo.close
// fos.close()
val writer = new PrintWriter(file);
writer.write(ret.toJson.compactPrint);
writer.close();
ret
}