从内存中的 ASCII 而不是从文件连接反序列化对象
Unserialize objects from in-memory ASCII instead of from a file connection
真题
如何将对象序列化为 ASCII 并从 ASCII 中再次反序列化它们 而无需 写入和读取文件连接(即从内存中的 ASCII)?
背景
在无状态的客户端-服务器框架中,我想让某些信息在跨调用时持久化(序列化 >> 发送到客户端 >> 从客户端获取序列化信息 >> 反序列化) 而不是在服务器端缓存它。
请注意,我的 JSON object/strong 还包含 其他未序列化的 信息,因此与序列化信息混合,这就是 [=] 中解释的方法的原因19=] 并不能完全解决问题。
现在,问题是我想反序列化 仅基于已读取的JSON 字符串的对象。可以这么说:来自 "in-memory ASCII" 而不是来自文件连接。我该怎么做?
这是我尝试过的:
require(forecast)
方法一
## 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()
的调用,而不仅仅是 re-establishing/unserializing 对象(注意打印到控制台的跟踪信息,我将其作为注释包含在内)。
这不完全是我想要的,只是想以最快的方式重新建立最终模型对象。
这就是我转向serialize()
下一步的原因。
方法二
## 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()
需要文件连接而不是 "plain ASCII"。
所以这就是我需要执行以下解决方法的原因。
方法 3
## 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 object/string.
实际发送
这符合您的需求吗?
它遵循您的方法 2 中的总体策略。唯一的区别是它使用 as.character()
将序列化对象转换为字符向量,然后再将其传递给 toJSON()
,然后使用 as.raw(as.hexmode())
将其转换回原始向量 "on the other side". (我用 ## <<- 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 并从 ASCII 中再次反序列化它们 而无需 写入和读取文件连接(即从内存中的 ASCII)?
背景
在无状态的客户端-服务器框架中,我想让某些信息在跨调用时持久化(序列化 >> 发送到客户端 >> 从客户端获取序列化信息 >> 反序列化) 而不是在服务器端缓存它。
请注意,我的 JSON object/strong 还包含 其他未序列化的 信息,因此与序列化信息混合,这就是 [=] 中解释的方法的原因19=] 并不能完全解决问题。
现在,问题是我想反序列化 仅基于已读取的JSON 字符串的对象。可以这么说:来自 "in-memory ASCII" 而不是来自文件连接。我该怎么做?
这是我尝试过的:
require(forecast)
方法一
## 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()
的调用,而不仅仅是 re-establishing/unserializing 对象(注意打印到控制台的跟踪信息,我将其作为注释包含在内)。
这不完全是我想要的,只是想以最快的方式重新建立最终模型对象。
这就是我转向serialize()
下一步的原因。
方法二
## 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()
需要文件连接而不是 "plain ASCII"。
所以这就是我需要执行以下解决方法的原因。
方法 3
## 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 object/string.
这符合您的需求吗?
它遵循您的方法 2 中的总体策略。唯一的区别是它使用 as.character()
将序列化对象转换为字符向量,然后再将其传递给 toJSON()
,然后使用 as.raw(as.hexmode())
将其转换回原始向量 "on the other side". (我用 ## <<- 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