- 浏览: 462728 次
- 性别:
- 来自: 坚持零分
文章分类
最新评论
-
wzwahl36:
文章非常赞,http://www.atool.org/img2 ...
在浏览器中解析Base64编码图像 -
realyasswl:
ie sucks
IE9 媲美Firebug的强大的程序员开发工具 -
di1984HIT:
不错啊。呵呵。
MS的一些小工具 -
NothingCanBeDone:
楼主,你这Project,能放出来了,感激不尽。
[Ray Linn]用Visual Studio 2008开发IE BHO(浏览器帮助对象) 之三 -
烬难烬:
这就没了???我去....
IE9 媲美Firebug的强大的程序员开发工具
代理编程
上面的斐波那契数列的例子只是展示了一个微不足道的构建数据流网的例子。这类网络适合那些“数据流入,数据流出”的场景,但它不能指定数据如何在网络中传播,也不允许不同类型的数据流入或者流出网络。
代理与通道给了我们创建复杂数据流网所需的一切。
通过通道沟通的两个代理是种弱关系:它不需要知道或关系另一个代理是如何实现的。它们之间的“契约”只由通道指定。借用OOP中的概念,通道扮演了接口的角色,而代理则是实现了该接口的类。
使用通道时,你向输入端口发送数据,从输出端口接受数据,这里,输入端口扮演了目标,而输出端口扮演了源头。而实现通道时,输入端口则是源头,输出端口则是目标。这有点难以理解,想想家里的水处理机,如果水是数据的话,考虑水的流向,你把水倒入入水口(水相对于你是流出),从出水口接水(水相对于你是流入),而处理机内部而言,水则是从进水口流入,从出水口流出。
请看例子,有个“Adder”通道接受输入两个数字并得出二者之和。通道的使用者发送数字到输入端口Num1和Num2,并从输出端口Sum接收结果。MainAgent代理是通道的使用者,而AdderAgent实现了该通道。
通道用关键字“channel”定义,端口则用关键字“input”和“output"定义。如果你仔细读过前面的文字,这些代码应该不难理解,不再赘述。
Schemas
不是所有的数据都能用通道来传送,原因有二:
1.在分布式场景中,代理可能存在两个不同进程中,甚至是两台机器上,传送的数据都必须被系列化。
2.Axum的孤立模式要求两个代理并发执行时不存取共享的可变状态。要满足这个条件,消息中的数据必须不是共享或可变的,否则代理不能并发执行。
为了满足这些要求,Axum引入了schema的概念,Schema是种类型,用于定义必需的或可选的字段,但不包含方法。这个概念与XML schema概念非常相似,或着说有点类似C#中的struct.
当消息中的schema的实例越过进程或者计算机的边界时,数据的有效载荷被深度系列化,这意味着你只能在schema中定义那些能用.NET-serialization系列化的字段。当消息在进程内传送的时候,则不需要深度系列化,但schema中的字段会被视为不可变的。Schema用关键字“schema”定义,随后跟着schema的名称:
“必需”与“可选”字段的区别允许不同schema之间,或者同形(same shape)的schema和类型之间的松耦合。同形意味着schema必须有相同的“必需”字段,但不要求必须有相同的“可选”字段。
当沟通各方未使用相同类型的schema的时候,这就很有用了。当系统的一个组件更新成新版本,schema发生了变化,但其仍可以被转换或强制成另一种近似的类型以便与其他组件继续通讯。比如这个C#类
如果编译时,编译器知道这种强制转换会失败的话,Axum编译器将报错,反之,编译器将产生代码,但这些代码可能在运行时报错的。schema还可以将许多不同的数据类型包装成一个单一的包装类型以便在一个消息中一次发送。
请求/回答端口
回顾上面的例子,它只能接受一次请求,之后代理AdderAgent就关闭了。我们可以修改AdderAgent让它继续接受新的起请求直到满足某些条件才关闭。这是个好的开始,不过如果我们希望用户能够提交多个请求,并按发送顺序接受这些请求,这该怎么办?为此,我们需要某种方法来关键请求与AdderAgent产生的结果。一个方法是返回个收据给客户端,客户端稍后凭此来认领结果。在Axum种,这种收据被称为请求关联(request correlator),支持请求关联的端口则成为请求/回答端口(request-reply ports).我们接下来修改上面的例子
正如你所看到的,向Adder提交请求同时产生了请求关联(correlator1 and correlator2),以用来取得结果.(很自然的,用receive表达式).
在例子中,因为我们提交了多个请求,当这些请求被处理的时候,我们有更多时间完成其他事。
协议
回顾下上上个例子,如果Adder使用不正确,AdderAgent和MainAgent会彼此等待对方的消息,导致死锁。如果用户在向Num2端口发送数据前,忘记给Num1发送数据,这时会发生什么?MainAgent继续企图读取结果,但同时AdderAgent能继续等待来自端口Num1的消息。
现在我们遇上了一个经典的死锁:MainAgent等待来自AdderAgent的消息,而AdderAgent又在等待来自MainAgent的消息。谁也没法继续执行。
直觉上我们知道第一条消息应该假定发送给Num1,跟着的第二条消息则应该是给Num2的。把我们的直觉形式化下来,就是通道该如何按照通道的协议工作了。协议是有限状态机,带有状态和通道设计者定义的状态间的变换。协议开始通常带有一个特殊的状态“开始。当心的消息到达通道的任何端口,协议将变换成任一协议定义的有效状态或触发一个违背协议异常,如果无任何有效状态存在。
我们将展示如何给通道Adder写一个协议。
开始协议带有状态“Start”,当端口Num1收到一条消息时,状态变换成GotNum1,如果其他端口在这时得到消息将导致违反协议异常。接下来,状态变成GotNum1,下个被使用的端口应该是Num1,它将触发状态变迁成GotNum2.最后端口Sum上的消息将触发变迁成内建的状态"End"。这时,协议被关闭了,任何再试图向端口发送消息将触发异常。
你可以定义更详细描述的变迁来使协议更丰富,比如可以“当消息到达端口X或Y,变迁到状态Y”或者“当消息的值大于10的时候,变迁到状态X"等等。为简单起见,我们不做详述,你可参考Axum的规格书。
我们试着改变上上个例子,用上面带协议的通道并注释掉这行
协议会把本来难以检测的死锁变成直接的违背协议异常。你会得到一条运行时的错误:
“Invalid use of 'Num2' at this point in the conversation, i.e. in state 'Adder.Start'”
很遗憾,不过每一个死锁都可以用严格的协议来捕获。如果用户向Num1发送了数据,但忘记向Num2发送数据而直接试图从Sum得到结果。和以前一样,AdderAgent和MainAgent也会无法继续执行,但是,这不会被认为是违背协议因为你仍然可以向Num2发送消息来解开死锁。
版权所有,如有转载,请站内联系
上面的斐波那契数列的例子只是展示了一个微不足道的构建数据流网的例子。这类网络适合那些“数据流入,数据流出”的场景,但它不能指定数据如何在网络中传播,也不允许不同类型的数据流入或者流出网络。
代理与通道给了我们创建复杂数据流网所需的一切。
通过通道沟通的两个代理是种弱关系:它不需要知道或关系另一个代理是如何实现的。它们之间的“契约”只由通道指定。借用OOP中的概念,通道扮演了接口的角色,而代理则是实现了该接口的类。
使用通道时,你向输入端口发送数据,从输出端口接受数据,这里,输入端口扮演了目标,而输出端口扮演了源头。而实现通道时,输入端口则是源头,输出端口则是目标。这有点难以理解,想想家里的水处理机,如果水是数据的话,考虑水的流向,你把水倒入入水口(水相对于你是流出),从出水口接水(水相对于你是流入),而处理机内部而言,水则是从进水口流入,从出水口流出。
请看例子,有个“Adder”通道接受输入两个数字并得出二者之和。通道的使用者发送数字到输入端口Num1和Num2,并从输出端口Sum接收结果。MainAgent代理是通道的使用者,而AdderAgent实现了该通道。
channel Adder { input int Num1; input int Num2; output int Sum; } agent AdderAgent : channel Adder { public AdderAgent() { int result = receive(PrimaryChannel::Num1) + receive(PrimaryChannel::Num2); PrimaryChannel::Sum <-- result; } } agent MainAgent : channel Microsoft.Axum.Application { public MainAgent() { var adder = AdderAgent.CreateInNewDomain(); adder::Num1 <-- 10; adder::Num2 <-- 20; // do something useful ... var sum = receive(adder::Sum); Console.WriteLine(sum); PrimaryChannel::ExitCode <-- 0; } }
通道用关键字“channel”定义,端口则用关键字“input”和“output"定义。如果你仔细读过前面的文字,这些代码应该不难理解,不再赘述。
Schemas
不是所有的数据都能用通道来传送,原因有二:
1.在分布式场景中,代理可能存在两个不同进程中,甚至是两台机器上,传送的数据都必须被系列化。
2.Axum的孤立模式要求两个代理并发执行时不存取共享的可变状态。要满足这个条件,消息中的数据必须不是共享或可变的,否则代理不能并发执行。
为了满足这些要求,Axum引入了schema的概念,Schema是种类型,用于定义必需的或可选的字段,但不包含方法。这个概念与XML schema概念非常相似,或着说有点类似C#中的struct.
当消息中的schema的实例越过进程或者计算机的边界时,数据的有效载荷被深度系列化,这意味着你只能在schema中定义那些能用.NET-serialization系列化的字段。当消息在进程内传送的时候,则不需要深度系列化,但schema中的字段会被视为不可变的。Schema用关键字“schema”定义,随后跟着schema的名称:
schema Customer { required string Name; optional string Address; }
“必需”与“可选”字段的区别允许不同schema之间,或者同形(same shape)的schema和类型之间的松耦合。同形意味着schema必须有相同的“必需”字段,但不要求必须有相同的“可选”字段。
当沟通各方未使用相同类型的schema的时候,这就很有用了。当系统的一个组件更新成新版本,schema发生了变化,但其仍可以被转换或强制成另一种近似的类型以便与其他组件继续通讯。比如这个C#类
class CustomerData { public string Name; } Customer c = new Customer{Name = "Artur", Address = "One Microsoft Way"}; CustomerData cd = coerce<CustomerData>(c);
如果编译时,编译器知道这种强制转换会失败的话,Axum编译器将报错,反之,编译器将产生代码,但这些代码可能在运行时报错的。schema还可以将许多不同的数据类型包装成一个单一的包装类型以便在一个消息中一次发送。
请求/回答端口
回顾上面的例子,它只能接受一次请求,之后代理AdderAgent就关闭了。我们可以修改AdderAgent让它继续接受新的起请求直到满足某些条件才关闭。这是个好的开始,不过如果我们希望用户能够提交多个请求,并按发送顺序接受这些请求,这该怎么办?为此,我们需要某种方法来关键请求与AdderAgent产生的结果。一个方法是返回个收据给客户端,客户端稍后凭此来认领结果。在Axum种,这种收据被称为请求关联(request correlator),支持请求关联的端口则成为请求/回答端口(request-reply ports).我们接下来修改上面的例子
using System; using System.Concurrency; using Microsoft.Axum; schema Pair { required int Num1; required int Num2; } channel Adder { input Pair Nums : int; // input request-reply port } agent AdderAgent : channel Adder { public AdderAgent() { while(true) { var result = receive(PrimaryChannel::Nums); result <-- result.RequestValue.Num1 + result.RequestValue.Num2; } } } agent MainAgent : channel Microsoft.Axum.Application { public MainAgent() { var adder = AdderAgent.CreateInNewDomain(); var correlator1 = adder::Nums <-- new Pair{ Num1=10, Num2=20 }; var correlator2 = adder::Nums <-- new Pair{ Num1=30, Num2=40 }; // do something useful here ... var sum1 = receive(correlator1); Console.WriteLine(sum1); var sum2 = receive(correlator2); Console.WriteLine(sum2); PrimaryChannel::ExitCode <-- 0; } }
正如你所看到的,向Adder提交请求同时产生了请求关联(correlator1 and correlator2),以用来取得结果.(很自然的,用receive表达式).
在例子中,因为我们提交了多个请求,当这些请求被处理的时候,我们有更多时间完成其他事。
协议
回顾下上上个例子,如果Adder使用不正确,AdderAgent和MainAgent会彼此等待对方的消息,导致死锁。如果用户在向Num2端口发送数据前,忘记给Num1发送数据,这时会发生什么?MainAgent继续企图读取结果,但同时AdderAgent能继续等待来自端口Num1的消息。
现在我们遇上了一个经典的死锁:MainAgent等待来自AdderAgent的消息,而AdderAgent又在等待来自MainAgent的消息。谁也没法继续执行。
直觉上我们知道第一条消息应该假定发送给Num1,跟着的第二条消息则应该是给Num2的。把我们的直觉形式化下来,就是通道该如何按照通道的协议工作了。协议是有限状态机,带有状态和通道设计者定义的状态间的变换。协议开始通常带有一个特殊的状态“开始。当心的消息到达通道的任何端口,协议将变换成任一协议定义的有效状态或触发一个违背协议异常,如果无任何有效状态存在。
我们将展示如何给通道Adder写一个协议。
channel Adder { input int Num1; input int Num2; output int Sum; Start: { Num1 -> GotNum1; } GotNum1: { Num2 -> GotNum2; } GotNum2: { Sum -> End; } }
开始协议带有状态“Start”,当端口Num1收到一条消息时,状态变换成GotNum1,如果其他端口在这时得到消息将导致违反协议异常。接下来,状态变成GotNum1,下个被使用的端口应该是Num1,它将触发状态变迁成GotNum2.最后端口Sum上的消息将触发变迁成内建的状态"End"。这时,协议被关闭了,任何再试图向端口发送消息将触发异常。
你可以定义更详细描述的变迁来使协议更丰富,比如可以“当消息到达端口X或Y,变迁到状态Y”或者“当消息的值大于10的时候,变迁到状态X"等等。为简单起见,我们不做详述,你可参考Axum的规格书。
我们试着改变上上个例子,用上面带协议的通道并注释掉这行
adder::Num1 <-- 10;
协议会把本来难以检测的死锁变成直接的违背协议异常。你会得到一条运行时的错误:
“Invalid use of 'Num2' at this point in the conversation, i.e. in state 'Adder.Start'”
很遗憾,不过每一个死锁都可以用严格的协议来捕获。如果用户向Num1发送了数据,但忘记向Num2发送数据而直接试图从Sum得到结果。和以前一样,AdderAgent和MainAgent也会无法继续执行,但是,这不会被认为是违背协议因为你仍然可以向Num2发送消息来解开死锁。
版权所有,如有转载,请站内联系
评论
2 楼
cuiguanglei
2009-08-09
我对代理这块了解不是很深,改天得详细作下试验才成啊。哈哈
1 楼
cuiguanglei
2009-08-09
不错,好文章。为什么不讨论JAVA方面的技术类。
发表评论
-
NET 4.0 多任务编程 之三 改进的线程池
2010-07-16 14:58 2228其实从.NET设计之初中就 ... -
NET 4.0 多任务编程 之四 Parallel初体验
2010-07-16 14:23 2164在.NET Framework 4.0中,在 ... -
.NET 4.0 多任务编程 之二 线程安全的集合
2010-07-14 13:54 3463随着多核计算机的普及 ... -
【C#】在C#中引用CygWin和MingW的Dll
2010-06-20 08:47 0在Windows上引入Unix或Linux的软件包,一般有以下 ... -
Java 7 闭包 -- 向C#学得更多
2010-06-08 10:55 210什么是闭包 简单来讲,闭包允许你将一些行为(包括语法和表达式 ... -
【Ray谈C#] MEF 扩展性管理框架
2010-05-28 16:58 3990原文发表于:blogs.ejb.cc M ... -
【Ray谈C#】乌龟爬之SynchronizationContexts
2010-05-19 15:09 2090为什么需要SynchronizationC ... -
用DLR创建自己的语言之一
2010-01-04 14:35 2536原文刊登于: http://www.bitwisemag.co ... -
C# 语法书 之可选参数
2009-12-22 14:40 2936适用C#版本:4.0以后 首 ... -
C# 语法书 <3> 静态类,别名等等
2009-06-30 11:32 1757最近比较忙,所以先跳 ... -
初窥Nemerle语言
2009-06-23 14:23 1741Nemerle是Microsoft的研究项目之一,由 Wroc ... -
C# 语法书 <2> 委托 delegate
2009-06-15 16:40 1883为什么要有委托? 先 ... -
C# 语法书 之 <1> 迭代器
2009-06-09 16:42 1331这个系列的主要目的是尽量能覆盖C# 1.1之后的语法更新,以便 ... -
What's New in C# 4.0 之一 语法
2009-06-08 14:54 23991. dynamic简介 在之前的文章有简单的谈到dynam ... -
What's New in .net 4.0 - 基础类库
2009-06-01 10:34 11481. System.Numerics.BigInteger ... -
一切为了并行:MS Axum语言教程 <四>
2009-05-14 15:12 1214数据流网编程 在程序中,代理之间通过发送和接受消息彼此沟通, ... -
一切为了并行: MS Axum语言教程 <三>
2009-05-13 14:35 1415域与状态共享 消息传递是种优秀的沟通机制,但它要消息中的数据 ... -
一切为了并行:MS Axum语言教程 <一>
2009-05-12 10:47 1453原文和更新参见: Ray Li ... -
C# 4.0中的契约式编程
2009-04-24 11:19 2882一切从质量谈起 许多 ... -
C# 利用范型与扩展方法重构代码
2008-04-03 14:58 2611在一些C#代码中常常可以看到 //An Simple Ex ...
相关推荐
1. axum框架概述:axum是一个用RUST编程语言编写的web框架,它是一个高性能、异步的框架,可以让我们更便捷地构建web应用。 2. 环境搭建:在开始使用axum之前,需要先搭建好RUST的开发环境,并安装好axum相关的依赖...
《Axum程序员指南》是一本深入探讨Axum编程语言的专业书籍,主要面向正在学习或已经从事Axum开发的程序员。Axum是由微软开发的一种新型的、高性能的、并发友好的编程语言,它旨在提高现代多核处理器环境下的软件开发...
OpenTelemetry Rust Rust 实现。||概述OpenTelemetry是工具,API和SDK的集合,用于检测,生成,收集和...(), Box < dyn>> { // Create a new instrumentation pipeline let tracer = stdout :: new_pipeline (). insta
You can start with the example actix-app, axum-app, dioxus-desktop or ntex-app. It requires Rust 1.75+ to build the project. cd examples/axum-app cargo run Here is the simplest application to run a ...
rust axumweb web rust,,redis,ormRibatis,casbin-rs, ,jwt casbin-rs websocket rust rust rust rust rust
在Rust编程语言中,处理HTTP请求特别是涉及文件上传时,`multipart`是一个非常重要的库。这个库提供了与后端无关的解决方案,使得开发者能够轻松地在HTTP客户端和服务器之间处理多部分表单数据,包括文件上传。在这...
它包括拉利贝拉(Lalibela)的岩石凿成教堂,阿克苏姆(Axum)方尖碑和哈拉尔(Harar)朱古拉斯主题。 我选择这个主题是因为我在EIABC校园学习,所以发现这个主题与我们所从事的领域以及课程的类型非常相关,因为...
基于Rust语言的新一代组装式应用开发框架,它强调 简单性、可扩展性和生产力。用于快速应用程序开发的开箱即用功能。最小设计、可组合架构和高级抽象。采用 API 优先的 approch 进行具有开放标准的开发。采用实用的...
基于Rust语言的新一代组装式应用开发框架。zino是 Rust 中可组合应用程序的下一代框架 它强调简单性、可扩展性和生产力。开箱即用的功能,可快速开发应用程序。最小的设计、可组合的架构和高级抽象。采用 API 优先的...
Rust是一种系统级编程语言,它专注于速度、内存安全和并行性,被广泛用于构建高性能软件,尤其是网络服务、操作系统组件以及游戏引擎。 描述中提到,创建者由于曾经丢失了所有C语言的源代码,因此决定将Rust项目...
此版本升级Axum至0.6.6,并消除2/3的编译警告。此版本支持Go语言通用代码生成器仙童的模板直接生成Rust代码生成物。也支持Java兼容性。支持Excel,PDF数据导出。支持Vue,ElementUI的独立前端。支持MySQL,MariaDB和...
它在科学界享有极高的声誉,以其丰富的功能和灵活性著称,尽管学习曲线相对陡峭,但相比竞争对手如SPSS的SigmaPlot和MathSoft的Axum,Origin提供了更多的功能。Origin的主要版本包括5.0、6.0、6.1、7.0和7.5,而描述...
本项目是一款基于Java实现的Rust通用代码生成器,代码名为“莲花”。...代码生成器依赖Axum 0.6.20、Tokio 1.32.0、sqlx 0.7.1等库,并支持连接MariaDB、MySQL 8、PostgreSQL、Oracle等多种数据库。
async fn add_number(_ctx: Context<'_>, number: i32) -> i32 { number * 2 } } ``` 在这个例子中,我们定义了一个名为`Query`的对象类型,它有一个名为`hello`的字段,以及一个名为`Schema`的突变,包含`add_...
WebDAV Handler库,以`webdav-handler-rs`命名,是专为Rust编程语言设计的一个高效、灵活的处理程序库。该库的主要目标是支持与HTTP服务器框架如Hyper、Warp以及Actix-Web等无缝集成,提供WebDAV协议的实现。WebDAV...
为了适应海量规模存储环境的要求,设计并实现了一种块级别的带内存储虚拟化系统(AXUM)。它使用连续空间段来组织虚拟盘和物理盘,减少了元数据的空间开销。并通过实现目标器模式的虚拟化服务,提供良好的兼容性。...
“不那么难” OAuth2客户端OAuth2确实不那么难,您知道吗? 文档许可证版权所有:copyright:2015,Curtis McEnroe,[受电子邮件保护]“不那么难” OAuth2客户端OAuth2确实不那么难,您知道吗? 文档许可证版权:...
RustJavaRust rust 1.69Axum 0.6.20Tokio 1.32.0sqlx 0.7.1MariaDB, MySQL 8, PostgreSQLOracle
尽管其学习曲线相对较陡峭,但Origin提供的强大功能使其在同类软件中独树一帜,与SPSS Scientific的SigmaPlot和MathSoft的Axum等竞争产品相比,Origin具有更多的数据分析和绘图选项。 Origin的核心功能分为两大部分...