从内存中的ASCII(而不是文件连接)反序列化对象 [英] Unserialize objects from in-memory ASCII instead of from a file connection
问题描述
如何将对象序列化为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屋!