![运送马匹](https://img-blog.csdnimg.cn/img_convert/38373d53826de6b1847309d0f3a4f964.png)
运送马匹
现在,无服务器区域中的服务即服务(FaaS)功能日趋流行,它正在提供新的机会,可以将功能即时发送给服务器,并且它将立即开始执行。
这有助于快速构建适应不断变化的用户需求的应用程序。Function_as_a_service是Amazon,Microsoft,Google等云提供商的热门产品。
FaaS与Actor模型有很多相似之处,后者讨论向Actor发送消息并执行本地操作,如果代码也可以像数据一样对待,那么代码也可以发送到远程进程,并且可以在本地执行功能。
我记得乔·阿姆斯特朗(Joe Armstrong)在谈论他构建Erlang时是如何将功能发送到服务器成为HTTP服务器或smtp服务器等的。他在1986年这样做!
让我们看一下如何保存可执行函数并在以后执行它。我将以Java为例,但是可以使用允许动态链接的任何语言来完成。 Javascript将绝对是动态链接的赢家。
快速修订
让我们快速看一下Java中的函数/行为
@Test
public void square_number() {
Function<Integer, Integer> sqr = x -> x * x;
assertEquals(4, sqr.apply(2));
assertEquals(9, sqr.apply(3));
assertEquals(16, sqr.apply(4));
}
@Test
public void to_upper() {
Function<String, String> upper = x -> x.toUpperCase();
assertEquals("FAAS", upper.apply("FaaS"));
}
上面的代码没什么要解释的,这是非常基本的转换。
保存功能
让我们尝试保存这些功能之一,然后看看会发生什么。
@Test
public void save_function() throws Exception {
Function<String, String> upper = x -> x.toUpperCase();
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bos)) {
os.writeObject(upper);
}
}
上面的代码看起来很完美,但是在运行时失败,出现以下错误
java.io.NotSerializableException:faas.FunctionTest $$ Lambda $ 266/1859039536 at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)at faas.FunctionTest。在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)处的save_function(FunctionTest.java:39)
Lambda函数默认情况下不可序列化。Java有一个很好的技巧,可以使用强制转换表达式添加其他绑定,有关更多详细信息,请参见强制表达式。
简而言之,如下所示
@Test()
public void save_function_works() throws Exception {
// Addtional casting allow to mark as serilized
Function<String, String> upper = (Function<String, String> & Serializable) x -> x.toUpperCase();
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bos)) {
os.writeObject(upper);
try (ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream in = new ObjectInputStream(bis)) {
Function<String, String> restoredUpper = (Function<String, String>) in.readObject();
Assertions.assertEquals("FAAS", restoredUpper.apply("FaaS"));
}
}
}
此技术允许将任何功能接口转换为字节,并在以后重用。 它在JDK的TreeMap / TreeSet等各个地方使用,因为这些数据结构具有比较器功能,还支持序列化。通过基本的工作,让我们尝试构建更有用的东西。
我们必须隐藏和序列化魔术以使代码更易读,而这可以通过从基本接口扩展并添加可序列化的功能接口来实现,如下所示
@FunctionalInterface
public interface SerFunction<T, R> extends Function<T, R>, Serializable {
}
@FunctionalInterface
public interface SerPredicate<T> extends Predicate<T>, Serializable {
}
....
一旦我们处理好样板,那么编写准备序列化的功能就变得非常容易。
List functions = asList(
SerCode.f((Integer x) -> x * x),
SerCode.f((String x) -> x.toUpperCase()),
SerCode.p((String x) -> x.length() > 5)
);
byte[] code = saveFunction(functions);
ObjectInputStream fStream = codeStream(code);
List rFunctions = (List) fStream.readObject();
int fIndex = 0;
Function<Integer, Integer> rSquare = (Function<Integer, Integer>) rFunctions.get(fIndex++);
System.out.println(rSquare.apply(10)); // Shows 100
Function<String, String> rUpper = (Function<String, String>) rFunctions.get(fIndex++);
System.out.println(rUpper.apply("FaaS")); // Shows "FAAS
Predicate<String> rGt5Length = (Predicate<String>) rFunctions.get(fIndex++);
System.out.println(rGt5Length.test("I am greater than 5")); // Shows true
使用以上构建块,我们可以保存完整的转换(映射/过滤器/减少/收集等)并运送到服务器进行处理。 这还允许构建可以根据需要重新计算的计算。
Spark是一种分布式处理引擎,它使用这种类型的模式来保持转换功能,并在多个节点上进行计算。
因此,下次您要构建一些分布式处理框架时,请研究此模式或将其应用到极限,然后将已修补的功能发送到生产环境中的实时服务器以解决该问题。
邮局中使用的代码可在@ faas上获得
翻译自: https://www.javacodegeeks.com/2020/07/ship-your-function.html
运送马匹