从内存中的ASCII(而不是文件连接)反序列化对象 [英] Unserialize objects from in-memory ASCII instead of from a file connection

查看:59
本文介绍了从内存中的ASCII(而不是文件连接)反序列化对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何将对象序列化为ASCII并再次从ASCII中反序列化它们,而无需写入和读取文件连接(即从内存中的ASCII)?

How can I serialize objects to ASCII and unserialize them again from ASCII without having to write to and read from a file connection (i.e. from ASCII that is in-memory)?

在无状态的客户端-服务器框架中,我想使某些信息在调用过程中持久化(序列化>>发送给客户端>>从客户端获取序列化的信息>>反序列化),而无需将其缓存在服务器端.

In a state-less client-server framework, I would like to make certain information persistent accross calls (serialize >> send to client >> get serialized info back from client >> unserialize) without caching it on the server side.

请注意,我的JSON对象/strong还包含其他未序列化的信息,因此与序列化信息混合在一起,这就是为什么

Note that my JSON object/strong also contains other unserialized information and is thus mixed with the serialized information which is why the approach explained in this post doesn't completely do the trick.

现在,问题是我想仅基于已读取的JSON字符串对对象进行反序列化.可以这么说:来自内存中的ASCII",而不是来自文件连接.我该怎么办?

Now, the thing is that I would like to unserialize the object solely based on the already-read JSON string. So to speak: from "in-memory ASCII" instead of from a file connection. How would I do that?

这是我尝试过的:

require(forecast)

方法1

## SERVER: estimates initial model and writes JSON to socket
model <- auto.arima(AirPassengers, trace = TRUE)

## Model trace:
# ARIMA(2,1,2)(1,1,1)[12]                    : Inf
# ARIMA(0,1,0)(0,1,0)[12]                    : 967.6773
# ARIMA(1,1,0)(1,1,0)[12]                    : 965.4487
# ARIMA(0,1,1)(0,1,1)[12]                    : 957.1797
# ARIMA(0,1,1)(1,1,1)[12]                    : 963.5291
# ARIMA(0,1,1)(0,1,0)[12]                    : 956.7848
# ARIMA(1,1,1)(0,1,0)[12]                    : 959.4575
# ARIMA(0,1,2)(0,1,0)[12]                    : 958.8701
# ARIMA(1,1,2)(0,1,0)[12]                    : 961.3943
# ARIMA(0,1,1)(0,1,0)[12]                    : 956.7848
# ARIMA(0,1,1)(1,1,0)[12]                    : 964.7139
# 
# Best model: ARIMA(0,1,1)(0,1,0)[12]  

fc <- as.data.frame(forecast(model))
deparsed <- deparse(model)

json_out <- list(data = AirPassengers, model = deparsed, fc = fc)
json_out <- jsonlite::toJSON(json_out)

## CLIENT: keeps estimated model, updates data, writes to socket
json_in <- jsonlite::fromJSON(json_out)
json_in$data <- window(AirPassengers, end = 1949 + (1/12 * 14))

## SERVER: reads new JSON and applies model to new data
data <- json_in$data
model_0 <- json_in$model
model_1 <- eval(parse(text = model_0))

## Model trace:
# ARIMA(2,1,2)(1,1,1)[12]                    : Inf
# ARIMA(0,1,0)(0,1,0)[12]                    : 967.6773
# ARIMA(1,1,0)(1,1,0)[12]                    : 965.4487
# ARIMA(0,1,1)(0,1,1)[12]                    : 957.1797
# ARIMA(0,1,1)(1,1,1)[12]                    : 963.5291
# ARIMA(0,1,1)(0,1,0)[12]                    : 956.7848
# ARIMA(1,1,1)(0,1,0)[12]                    : 959.4575
# ARIMA(0,1,2)(0,1,0)[12]                    : 958.8701
# ARIMA(1,1,2)(0,1,0)[12]                    : 961.3943
# ARIMA(0,1,1)(0,1,0)[12]                    : 956.7848
# ARIMA(0,1,1)(1,1,0)[12]                    : 964.7139
# 
# Best model: ARIMA(0,1,1)(0,1,0)[12]  

# Warning message:
#   In auto.arima(x = structure(list(x = structure(c(112, 118, 132,  :
#       Unable to fit final model using maximum likelihood. AIC value approximated

fc <- as.data.frame(forecast(Arima(data, model = model_1)))

## And so on ...

可以,但是请注意eval(parse(text = json_in$model))实际上重新运行auto.arima()的调用,而不仅仅是重新建立/反序列化对象(请注意,打印到控制台的跟踪信息包含在评论中).

That works, but note that eval(parse(text = json_in$model)) actually re-runs the call to auto.arima() instead of just re-establishing/unserializing the object (note the trace information printed to the console that I included as comments).

这不是我想要的,只是想以最快的方式重新建立最终的模型对象.

That's not completely what I want as simply want to re-establish the final model object in the fastest possible way.

这就是为什么我接下来转向serialize()的原因.

That's why I turned toserialize() next.

## SERVER: estimates initial model and writes JSON to socket
model <- auto.arima(AirPassengers, trace = TRUE)
fc <- as.data.frame(forecast(model))
serialized <- serialize(model, NULL)
class(serialized)

json_out <- list(data = AirPassengers, model = serialized, fc = fc)
json_out <- jsonlite::toJSON(json_out)

## CLIENT: keeps estimated model, updates data, writes to socket
json_in <- jsonlite::fromJSON(json_out)
json_in$data <- window(AirPassengers, end = 1949 + (1/12 * 14))

## SERVER: reads new JSON and applies model to new data
data <- json_in$data
model_0 <- json_in$model
try(model_1 <- unserialize(model_0))
## --> error:
# Error in unserialize(model_0) : 
#   character vectors are no longer accepted by unserialize()

不幸的是,函数unserialize()需要文件连接而不是纯ASCII".

Unfortunately, function unserialize() expects a file connection instead of "plain ASCII".

所以这就是为什么我需要执行以下解决方法的原因.

So that's why I need to do the following workaround.

## SERVER: estimates initial model and writes JSON to socket
model <- auto.arima(AirPassengers, trace = TRUE)
fc <- as.data.frame(forecast(model))
con <- file("serialized", "w+")
serialize(model, con)
close(con)

json_out <- list(data = AirPassengers, model = "serialized", fc = fc)
json_out <- jsonlite::toJSON(json_out)

## CLIENT: keeps estimated model, updates data, writes to socket
json_in <- jsonlite::fromJSON(json_out)
json_in$data <- window(AirPassengers, end = 1949 + (1/12 * 14))

## SERVER: reads new JSON and applies model to new data
data <- json_in$data
model_0 <- json_in$model
con <- file(model_0, "r+")
model_1 <- unserialize(con)
close(con)
fc <- as.data.frame(forecast(Arima(data, model = model_1)))

## And so on ...

反序列化现在可以正常运行,而无需重新评估实际的auto.arima()调用.但这违反了我的无状态范式,因为现在实际信息存储在服务器端,而不是通过JSON对象/字符串实际发送.

Unserializing works now without the actual auto.arima() call being re-evaluated. But it's against my state-less paradigm as now the actual information is cached on the server side instead of actually being sent via the JSON object/string.

推荐答案

这符合您的需求吗?

它遵循您的方法2 中的常规策略.唯一的区别是,它使用as.character()将序列化的对象转换为字符向量,然后再将其传递给toJSON(),然后使用as.raw(as.hexmode())将其转换为另一侧"的原始向量. (我已经在编辑的两行中标记了注释,其内容为## <<- Edited.)

It follows the general strategy in your Approach 2. The only difference is that it uses as.character() to convert the serialized object to a character vector before passing it to toJSON(), and then uses as.raw(as.hexmode()) to convert it back to a raw vector "on the other side". (I've marked the two edited lines with comments reading ## <<- Edited.)

library(forecast)

## SERVER: estimates initial model and writes JSON to socket
model <- auto.arima(AirPassengers, trace = TRUE)
fc <- as.data.frame(forecast(model))
serialized <- as.character(serialize(model, NULL)) ## <<- Edited
class(serialized)


json_out <- list(data = AirPassengers, model = serialized, fc = fc)
json_out <- jsonlite::toJSON(json_out)

## CLIENT: keeps estimated model, updates data, writes to socket
json_in <- jsonlite::fromJSON(json_out)
json_in$data <- window(AirPassengers, end = 1949 + (1/12 * 14))

## SERVER: reads new JSON and applies model to new data
data <- json_in$data
model_0 <- as.raw(as.hexmode(json_in$model))       ## <<- Edited

unserialize(model_0)
## Series: AirPassengers 
## ARIMA(0,1,1)(0,1,0)[12]                    
## 
## Coefficients:
##           ma1
##       -0.3184
## s.e.   0.0877
## 
## sigma^2 estimated as 137.3:  log likelihood=-508.32
## AIC=1020.64   AICc=1020.73   BIC=1026.39

这篇关于从内存中的ASCII(而不是文件连接)反序列化对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆