精华内容
下载资源
问答
  • 我们再前面创建通道的时候,通过configtx.yaml定义通道的基础配置包括 策略: 通道的读写权限策略等 Capabilities: 确保网络和通道以相同的方式处理交易,使用版本号进行定义。 Channel/Application: 控制...

    总目录:
    (0) 如何利用区块链保护知识产权
    (一)HyperLedger Fabric 2.0-release测试网络部署
    (二)Fabric2.0 first-network 生成配置说明
    (三)Fabric2.0启动网络脚本配置剖析
    (四)Fabric2.0通道实践
    (五)Fabric2.0 智能合约实践- 安装以及定义智能合约
    (六)Fabric2.0 智能合约实践- 升级智能合约
    (七)Fabric2.0智能合约实践-设置背书策略
    (八)Fabric2.0Java SDK实践-合约交易
    (九)Fabric2.0 通道实践-更新通道配置
    (十)Fabric2.0-动态添加组织
    (十一) Fabric2.0-使用编辑器调试go智能合约
    (十二)Fabric2.0-实现外部构建启动合约
    工具人大胆试探raft共识-你没见过的raft算法解释

    下面实践将基于已部署好的first-network.

    1.通道配置说明

    我们再前面创建通道的时候,通过configtx.yaml定义通道的基础配置包括

    • 策略:

    通道的读写权限策略等

    • Capabilities:

    确保网络和通道以相同的方式处理交易,使用版本号进行定义。

    • Channel/Application:

      控制应用程序通道的配置参数(添加/删除组织):修改这一部分配置需要大部分组织管理管理员的签名。
      将组织添加到通道:要实现添加到通道必须将组织的MSP等配置参数添加到组织配置,下一章将详细讲。
      组织相关参数:可以更改组织特定的任何参数(例如,标识锚点对等体或组织管理员的证书)。请注意,默认情况下,更改这些值将不需要大多数应用程序组织管理员,而仅需要组织本身的管理员
      
    • Channel/Orderer:

    控制排序节点相关参数

    • Batch size

      Batch size:这些参数决定了一个区块中交易的数量和大小。
      Batch timeout 在第一个交易到达其他交易之后,在切割区块之前要等待的时间。减小该值将改善等待时间,但是减小该值可能会由于不允许块填满其最大容量而降低吞吐量。
      Block validation: 该策略指定了被视为有效的块的签名要求。默认情况下,它需要订购组织的某些成员的签名。
      
    • Channel:

    控制peer跟orderer都需要同意的参数,需要大部分应用程序管理者同意

    orderer地址:客户端可以在其中调用orderer的Broadcast和Deliver功能的地址列表。peer在这些地址中随机选择,并在它们之间进行拉取块。
    Hashing structure :块数据是字节数组的数组。块数据的哈希计算为默克尔树。此值指定该Merkle树的宽度。目前,该值固定为4294967295。
    散列算法:用于计算编码到区块链块中的哈希值的算法。特别是,这会影响数据散列以及该块的先前的块散列字段。请注意,此字段当前只有一个有效值(SHA256),不应更改。
    Consensus type 共识类型: 为了能够将基于Kafka的orderer服务迁移到基于Raft的orderer服务,可以更改渠道的共识类型。
    

    2.更新通道

    2.1提取并解析通道配置

    更新通道配置的第一步是获取最新的配置块。这是一个三步过程。首先,我们将以protobuf格式提取通道配置,创建一个名为的文件config_block.pb。

    控制台数据docker exec -it cli bash进入cli

    peer channel fetch config config_block.pb -o $ORDERER_CONTAINER -c mychannel --tls --cafile $TLS_ROOT_CA
    

    控制台输入获取通道区块数码,并生成config_block.pb文件

    在这里插入图片描述

    .pb是protobuf格式,我们将他转成json版本

    继续再当前目录输入以下命令

    configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json
    
    --input .pb文件路径
    --output 转json格式后输出文件路径
    

    生成config_block.json文件

    在这里插入图片描述

    看一下输出的config_block.json文件,数据很多

    最后,我们将从配置中排除所有不必要的元数据,使其更易于阅读。您可以随意调用该文件,但是在本示例中,我们将其称为config.json。

    执行以下命令

    jq .data.data[0].payload.data.config config_block.json > config.json
    

    部分数据截取如下:
    在这里插入图片描述

    为了待会比较,我们先复制一份

    cp config.json modified_config.json
    

    2.2 修改配置

    修改Batch size,将区块最大交易数量提高,原本max_message_count是10,我们修改为100。
    原本:
    在这里插入图片描述

    vi modified_config.json
    

    修改后:
    在这里插入图片描述

    2.2 重新编码跟提交配置

    首先,我们将config.json文件恢复为protobuf格式,创建一个名为的文件config.pb。然后,我们将对我们的modified_config.json文件执行相同的操作。之后,我们将计算两个文件之间的差,创建一个名为的文件config_update.pb。

    configtxlator proto_encode --input config.json --type common.Config --output config.pb
    configtxlator proto_encode --input modified_config.json --type common.Config --output modified_config.pb
    configtxlator compute_update --channel_id mychannel --original config.pb --updated modified_config.pb --output config_update.pb
    

    现在我们已经计算出旧配置和新配置之间的差异config_update.pb,我们可以将更改应用于配置。

    configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output config_update.json
    

    查看差异配置

    在这里插入图片描述
    将差异配置重新编码

    echo '{"payload":{"header":{"channel_header":{"channel_id":"mychannel", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' | jq . > config_update_in_envelope.json
    configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope --output config_update_in_envelope.pb
    

    提交配置

    peer channel update -f config_update_in_envelope.pb -c mychannel -o $ORDERER_CONTAINER --tls true --cafile $TLS_ROOT_CA
    

    控制台输出:
    在这里插入图片描述

    implicit policy evaluation failed - 0 sub-policies were satisfied, but this policy requires 1 of the 'Admins' sub-policies to be satisfied

    上面的错误应该是很熟悉了,就是修改这个配置不够权限,提示需要Admin,由于batchSize属于排序节点的配置,所以这里的Admin是OrdererMSP.admin
    这里要注意一点的是 first-network的排序节点是没有区份admin、client这些需要再crypto-config.yaml打开配置如下:
    在这里插入图片描述

    切换OrdererMSP.admin环境变量如下:

    CORE_PEER_LOCALMSPID=OrdererMSP
    CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/users/Admin@example.com/msp/
    

    原本应该调用peer channel signconfigtx 进行签名的,但是peer channel update 的时候会自动带客户端签名,这里我们直接update就行了,因为他需要1个Admin而已

    控制台输入:

    peer channel update -f config_update_in_envelope.pb -c mychannel -o $ORDERER_CONTAINER --tls true --cafile $TLS_ROOT_CA
    

    输出结果如下:

    在这里插入图片描述
    通道配置更新成功

    3. 总结

    更新通道配置步骤主要是获取现有配置,修改配置,提交配置,看起来比较简单,但是有一点要留意的是权限问题,想刚刚上面就提示没有收集够签名,这时候我们应该关注日志输出内容,回顾我们原本configtx.yaml的配置,找到需要的签名,满足策略。

    推荐阅读:(十)Fabric2.0-动态添加组织

    展开全文
  • CNN图像通道数和卷积核的深度及数量的关系 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本...

    CNN图像通道数和卷积核的大小及数量的关系

    对于一张56×56×3的图片来说,3代表的就是输入图像的通道数,也可以理解为3张56×56的特征图,例如对一幅彩色图像来说,就代表R、G、B三颜色通道的特征图。因此对其进行卷积运算时,卷积核的深度就必须与输入图像的通道数相同,拿1×1卷积来说,卷积核的大小就必须是1×1×3。
    在这里插入图片描述
    上面的1×1×3中的3是进行卷积运算时的卷积核的大小,我初学时总是会将其和卷积核的数量相混淆,认为所谓1×1卷积的降维的作用就是通过这个参数来体现,因此专门在这里总结一下。实际上,当1×1×3卷积核的数量只有1个时,最终得到的输出图像的通道数为1。

    因此,控制输出图像通道数的是卷积核的数量,即1×1×3卷积核的数量,如下图所示。
    在这里插入图片描述
    【CNN】理解卷积神经网络中的通道 channel

    展开全文
  • 通道是什么  当你看到这个题目的时候,如果感到头疼的话,那么----这是帮你你彻底掌握通道的一个好机会,或许是你最后一次感到头疼了。  无论是在各类电脑杂志,还是网络媒体中,有关photoshop通道的各类...
    一 通道是什么 

    当你看到这个题目的时候,如果感到头疼的话,那么----这是帮你你彻底掌握通道的一个好机会,或许是你最后一次感到头疼了。 
    无论是在各类电脑杂志,还是网络媒体中,有关photoshop通道的各类文章可谓层出不穷,可依然有那么多人如堕五里雾中? 那么,通道是什么?可以这么说,通道就是选区。 
    听起来好象很简单(其实就这么简单),无论通道有多少种表示选区的方法,无论你看过多少种有关通道的解释,至少从现在开始,它就是选区。千万不要告诉我你从来不需要通道。当你用任何选择工具做了一个选择,试一下那个你应该很明白的存储选区命令,现在,是否意识到你已经成**的建立了一个通道?不接触通道,你不可能改动图象中的任何部分,这是我把通道列为这个专题最开始的原因。只有弄明白通道,你才能离开初学者的行列,向高手的境界前进。 
    当然我不会仅仅告诉你这些,那只是我为了下面的内容做的铺垫而已,毕竟任何方面的高手都不能只看到事物的表象。但不管你接着看到些什么内容,请时刻记住我上面告诉你的话。还记得是什么吗?没错,通道就是选区。 

    二 通道可以做什么 

    在通道中,记录了图象的大部分信息,这些信息从始至终与你的操作密切相关。具体看起来,通道的作用主要有: 
    ⑴ 表示选择区域,也就是白色代表的部分。利用通道,你可以建立头发丝这样的精确选区。 
    ⑵ 表示墨水强度。利用Info面板可以体会到这一点,不同的通道都可以用256级灰度来表示不同的亮度。在Red通道里的一个纯红色的点,在黑色的通道上显示就是纯黑色,即亮度为0。 
    ⑶ 表示不透明度。其实这是我们平时最乐于使用的一个**能。或许你曾经看到过一座高山渐隐融入到水中的图片?是不是也曾羡慕不已?那么,就记住通道吧,你爱它,它就会帮你。 
    ⑷ 表示颜色信息。不妨实验一下,预览Red通道,无论你的鼠标怎样移动,Info面板上都仅有R值,其余的都为0。 

    三 通道的分类 

    通道作为图象的组成部分,是与图象的格式密不可分的,图象颜色、格式的不同决定了通道的数量和模式,在通道面板中可以直观的看到。 
    在photoshop中涉及的通道主要有: 
    ⑴ 复合通道(Compound Channel) 
    复合通道不包含任何信息,实际上它只是同时预览并编辑所有颜色通道的一个快捷方式。它通常被用来在单独编辑完一个或多个颜色通道后使通道面板返回到它的默认状态。对于不同模式的图象,其通道的数量是不一样的。在photoshop之中,通道涉及三个模式。对于一个RGB图象,有RGB、R、G、B四个通道;对于一个CMYK 图象,有CMYK、C、M、Y、K五个通道;对于一个Lab模式的图象,有Lab、L、a、b四个通道。 
    ⑵ 颜色通道(Color Channel) 
    当你在photoshop中编辑图象时,实际上就是在编辑颜色通道。这些通道把图象分解成一个或多个色彩成分,图象的模式决定了颜色通道的数量,RGB模式有3个颜色通道,CMYK图象有4个颜色通道,灰度图只有一个颜色通道,它们包含了所有将被打印或显示的颜色。 
    ⑶ 专色通道(Spot Channel) 
    专色通道是一种特殊的颜色通道,它可以使用除了青色、洋红(有人叫品红)、黄色、黑色以外的颜色来绘制图象。因为专色通道一般人用的较少且多与打印相关,所以我把它放在后面的内容中讲述。 
    ⑷ Alpha通道(Alpha Channel) 
    Alpha 通道是计算机图形学中的术语,指的是特别的通道。有时,它特指透明信息,但通常的意思是“非彩色”通道。这是我们真正需要了解的通道,可以说我们在 photoshop中制作出的各种特殊效果都离不开Alpha通道,它最基本的用处在于保存选取范围,并不会影响图象的显示和印刷效果。当图象输出到视频,Alpha通道也可以用来决定显示区域。如果你曾经稍微深入到After Effects这类非线性编辑软件中去过,就会更加清楚。 
    ⑸ 单色通道 
    这种通道的产生比较特别,也可以说是非正常的。试一下,如果你在通道面板中随便删除其中一个通道,就会发现所有的通道都变成“黑白”的,原有的彩色通道即使不删除也变成灰度的了。 

    四 通道的编辑(大部分情况下是特指Alpha通道) 

    对图象的编辑实质上不过是对通道的编辑。因为通道是真正记录图象信息的地方,无论色彩的改变、选区的增减、渐变的产生,都可以追溯到通道中去。 
    对于特殊的编辑方法,在此不做介绍,看看常规的有哪些吧! 
    首先还要说明的是,鉴于通道的特殊性,它与其他很多工具有着千丝万缕的联系,比如蒙板。 言归正传,让我们一起来操作通道: 

    ⑴ 利用选择工具 
    photoshop 中的选择工具包括遮罩工具(Marquee)、套索工具(Lasso)、魔术棒(Magic Wand)、字体遮罩(Type Mask)以及由路径转换来的选区等,其中包括不同羽化值的设置。利用这些工具在通道中进行编辑与对一个图象的操作是相同的,你所需的仅仅是一点点勇气。 
    使用选择工具可以完成一些最基本的操作。 
    ⑵ 利用绘图工具 
    绘图工具包括喷枪(Airbrush)、画笔(Paintbrush)、铅笔(Pencil)、图章(Stamp)、橡皮擦(Eraser)、渐变(Gradient)、油漆桶(Paint Bucket)、模糊锐化和涂抹(Blur、Sharpen、Smudge)、加深减淡和海绵(Dodge、Burn、Sponge)。 
    现在应该很容易理解我们平时操作的通道所具备的颜色的问题。当你看到任何一种选择带来的白色时,就应该有一种用手指去涂抹一下的冲动。当然,这样做带来的后果也许只能改变你心爱的的显示屏的颜色,但你大可用画笔这类的工具作为替代品去实验一下,的确,任何选择区域你都可以用你随手可以捡到的绘图工具去创建,其间唯一的区别也许只是你看不到那些黑白相间不断行动的线条了。 
    利用绘图工具编辑通道的一个优势在于你可以精确的控制笔触(虽然比不上绘图板),从而可以得到更为柔和以及足够复杂的边缘。实际的去运用一下,你很快会喜欢上它们。现在我所做的每一幅图片,只要涉及通道,80% 以上时从画笔开始的。因为我并不需要一团黑或者一团白。 
    这里要提一下的,是渐变工具。因为这种工具比较特别。不是说它特别复杂,而是说它特别容易被人忽视。但相对于通道确又是特别的有用。它是我所知道的 photoshop中严格意义上的一次可以涂画多种颜色而且包含平滑过度的绘画工具,针对于通道而言,也就是带来了平滑细腻的渐变。当你要把自己完美的融合到大自然中去时,从这里开始是个不错的主意。 

    ⑶ 利用滤镜 
    在通道中进行滤镜操作,通常是在有不同灰度的情况下,而运用滤镜的原因,通常是因为我们刻意追求一种出乎意料的效果或者只是为了控制边缘。原则上讲,你可以在通道中运用任何一个滤镜去试验,当然这只是在你没有任何目的的时候,实际上大部分人在运用滤镜操作通道时通常有着较为明确的愿望,比如锐化或者虚化边缘,从而建立更适合的选区。各种情况比较复杂,需要根据目的的不同做相应处理,但你尽可试一下,总会有收获的。 

    ⑷ 利用调节工具 
    特别有用的调节工具包括色阶(level)和曲线(curves)。 
    在你用这些工具调节图象时,你会看到对话框上有一个channel选单,在这里可以所要编辑的颜色通道。当你选中希望调整的通道时,按住shift键,再单击另一个通道,最后打开图象中的复合通道。这样你就可以强制这些工具同时作用于一个通道。 
    对于编辑通道来说,这当然是有用的,但实际上并不常用的,因为你大可以建立调节图层而不必破坏最原始的信息。 
    再强调一点,单纯的通道操作是不可能对图象本身产生任何效果的,必须同其他工具结合,如选区和蒙板(其中蒙板是最重要的),所以再理解通道时最好与这些工具联系起来,才能知道你精心制作的通道可以在图象中起到什么样的作用。 

    五 补充 

    ⑴ 颜色通道中所记录的信息,从严格意义上说不是整个文件的,而是来自于我们当前所编辑的图层。预视一层的时候,颜色通道中只有这一层的内容,但如果同时预视多个层,则颜色通道中显示的是层混合后的效果。但由于我们一次仅能编辑一层,所以任何何使用颜色通道所做的变动只影响到当前选取的层。 
    ⑵ 当我们在通道面板上单击一个通道,对它进行预览的时候,将显示一幅灰度图象,你可以清楚的看到通道中的信息,但如果你同时打开多个通道,那么通道将以彩色显示。你可以打开显示与光标设置对话框,复选Clolr channel in color项,但我相信你最后会放弃这项当初看上去颇为重大的改动,因为你几乎找不到你原本能很容易找到的东西了。 
    ⑶ 有时候,你在通道中建立了一个自己十分满意的选择区域,但在图象中载入这个选区的时候却大惊失色:这根本和通道中的不一样嘛!或许吧,但千万不要对你自己产生怀疑,要知道你并没有犯任何错误,当然photoshop也没有错。要想弄明白这个道理,我们还是要从灰度入手。 
    做个实验,在一个新通道中选择一个区域,用51%的灰色填充;在同一个通道中新建一个选择,用49%的灰色填充,最后在图象中将这个通道作为选区载入。看到结果了吗?只有那处用小于 50%灰色显示出来了,而实际上,那处用大于50%灰色填充的区域并未消失,它同样也被选取了,你可以认为是那些灰度代表的透明度把选取本身也弄得透明了。所以,当你在把一个完全用大于50%灰色填充的通道作为选区载入的时候,没有什么好担心的,值得注意的不过是事先把音箱的音量调低,以免被那个弹出的警告框发出的声音吓到罢了。 
    ⑷ 想创建一个只有一边有羽化值的选区吗?到通道中试试看。建立一个选择(用矩形遮罩好理解一些),然后有渐变工具填充。载入这个通道吧!记住你看到的效果,回到通道中重新编辑那个选区。多试几次,你就会更明白通道都为你!!!!
    展开全文
  • NIO学习笔记——通道(channel)详解

    万次阅读 2017-06-25 00:50:16
    通道可以形象地比喻为银行出纳窗口使用的气动导管。您的薪水支票就是您要传送的信息,载体(Carrier)就好比一个缓冲区。您先填充缓冲区(将您的支票放到载体上),接着将缓冲“写”到通道中(将载体丢进导管中),...

    通道可以形象地比喻为银行出纳窗口使用的气动导管。您的薪水支票就是您要传送的信息,载体(Carrier)就好比一个缓冲区。您先填充缓冲区(将您的支票放到载体上),接着将缓冲“写”到通道中(将载体丢进导管中),然后信息负载就被传递到通道另一侧的 I/O 服务(银行出纳员)。该过程的回应是:出纳员填充缓冲区(将您的收据放到载体上),接着开始一个反方向的通道传输(将载体丢回到导管中)。载体就到了通道的您这一侧(一个填满了的缓冲区正等待您的查验),然后您就会 flip缓冲区(打开盖子)并将它清空(移除您的收据)。现在您可以开车走了,下一个对象(银行客户)将使用同样的载体(Buffer)和导管(Channel)对象来重复上述过程。
    从 Channel 接口引申出的其他接口都是面向字节的子接口,包括 Writable ByteChannel和ReadableByteChannel,并且通道只能在字节缓冲区上操作,操作系统都是以字节的形式实现底层I/O接口的。

    打开通道

    I/O可以分为广义的两大类别:File I/O 和 Stream I/O。那么相应地有两种类型的通道也就不足为怪了,它们是文件(file)通道和套接字(socket)通道,如下图所示
    这里写图片描述
    通道可以以多种方式创建。Socket通道有可以直接创建新socket通道的工厂方法。但是一个FileChannel 对象却只能通过在一个打开的 RandomAccessFile、FileInputStream 或 FileOutputStream对象上调用 getChannel( )方法来获取。您不能直接创建一个 FileChannel 对象。
    三种打开通道方式代码如下:

    /**
         * 演示打开通道的三种方式
         * fuyuwei
         * 2017年6月22日 下午9:38:00
         */
        public void openSocket(){
            try {
                // 1、打开一个套接字通道
                SocketChannel sc = SocketChannel.open();
                // 根据主机名和端口号创建套接字地址
                InetSocketAddress socketAddress = new InetSocketAddress("192.168.1.102",8080);
                // 连接套接字
                sc.connect(socketAddress);
    
                // 2、打开一个server-socket通道
                ServerSocketChannel ssc = ServerSocketChannel.open();
                ssc.socket().bind(new InetSocketAddress(8080));
    
                // 3、打开一个datagram通道
                DatagramChannel dc = DatagramChannel.open();
                RandomAccessFile raf = new RandomAccessFile("/usr/local/swk/dump.txt", "r");
                FileChannel fc = raf.getChannel();
    
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    

    使用通道

    通道将数据传输给 ByteBuffer 对象或者从 ByteBuffer 对象获取数据进行传输
    通道可以是单向( unidirectional)或者双向的( bidirectional)。一个 channel 类可能实现定义read( )方法的 ReadableByteChannel 接口,而另一个 channel 类也许实现 WritableByteChannel 接口以提供 write( )方法。实现这两种接口其中之一的类都是单向的,只能在一个方向上传输数据。如果一个类同时实现这两个接口,那么它是双向的,可以双向传输数据。
    我们知道,一个文件可以在不同的时候以不同的权限打开。从 FileInputStream 对象的getChannel( )方法获取的 FileChannel 对象是只读的,不过从接口声明的角度来看却是双向的,因为FileChannel 实现 ByteChannel 接口。在这样一个通道上调用 write( )方法将抛出未经检查的NonWritableChannelException 异常,因为 FileInputStream 对象总是以 read-only 的权限打开文件。
    通道会连接一个特定 I/O 服务且通道实例( channel instance)的性能受它所连接的 I/O 服务的特征限制,记住这很重要。一个连接到只读文件的 Channel 实例不能进行写操作,即使该实例所属的类可能有 write( )方法。
    ByteChannel 的 read( ) 和 write( )方法使用 ByteBuffer 对象作为参数。两种方法均返回已传输的字节数,可能比缓冲区的字节数少甚至可能为零。缓冲区的位置也会发生与已传输字节相同数量的前移。如果只进行了部分传输,缓冲区可以被重新提交给通道并从上次中断的地方继续传输。该过程重复进行直到缓冲区的 hasRemaining( )方法返回 false 值。如下代码我们演示如何从一个通道复制数据到另一个通道。

    public void copyChannel(){
            ReadableByteChannel source = Channels.newChannel(System.in);
            WritableByteChannel dest = Channels.newChannel(System.out);
            channelCopy1(source,dest);
            try {
                source.close();
                dest.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    
        private void channelCopy1(ReadableByteChannel src,
                WritableByteChannel dest) {
            // 分配一个新的直接字节缓冲区
            ByteBuffer buffer = ByteBuffer.allocateDirect(16*1024);
            try {
                while(src.read(buffer) != -1){
                    // 读转变成写模式
                    buffer.flip();
                    dest.write(buffer);
                    buffer.compact();
                }
                // 确保缓冲区完全排干
                while (buffer.hasRemaining( )) {
                    dest.write (buffer);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public void channelCopy2(ReadableByteChannel src,
                WritableByteChannel dest) {
            ByteBuffer buffer = ByteBuffer.allocateDirect (16 * 1024);
            try {
                while (src.read(buffer) != -1) {
                    // Prepare the buffer to be drained
                    buffer.flip();
                    // Make sure that the buffer was fully drained
                    while (buffer.hasRemaining()) {
                        dest.write(buffer);
                    }
                    // Make the buffer empty, ready for filling
                    buffer.clear();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    通道可以以阻塞( blocking)或非阻塞( nonblocking)模式运行。非阻塞模式的通道永远不会让调用的线程休眠。请求的操作要么立即完成,要么返回一个结果表明未进行任何操作。只有面向流的( stream-oriented)的通道,如 sockets 和 pipes 才能使用非阻塞模式。

    关闭通道

    与缓冲区不同,通道不能被重复使用。一个打开的通道即代表与一个特定 I/O 服务的特定连接并封装该连接的状态。当通道关闭时,那个连接会丢失,然后通道将不再连接任何东西。
    调用通道的close( )方法时,可能会导致在通道关闭底层I/O服务的过程中线程暂时阻塞 7,哪怕该通道处于非阻塞模式。通道关闭时的阻塞行为(如果有的话)是高度取决于操作系统或者文件系统的。在一个通道上多次调用close( )方法是没有坏处的,但是如果第一个线程在close( )方法中阻塞,那么在它完成关闭通道之前,任何其他调用close( )方法都会阻塞。后续在该已关闭的通道上调用close( )不会产生任何操作,只会立即返回。
    可以通过 isOpen( )方法来测试通道的开放状态。如果返回 true 值,那么该通道可以使用。如果返回 false 值,那么该通道已关闭,不能再被使用。尝试进行任何需要通道处于开放状态作为前提的操作,如读、写等都会导致 ClosedChannelException 异常。
    如果一个通道实现 InterruptibleChannel 接口它的行为以下述语义为准:如果一个线程在一个通道上被阻塞并且同时被中断,那么该通道将被关闭,该被阻塞线程也会产生一个 ClosedByInterruptException 异常。此外,假如一个线程的 interrupt status 被设置并且该线程试图访问一个通道,那么这个通道将立即被关闭,同时将抛出相同的 ClosedByInterruptException 异常。线程的 interrupt status 在线程的interrupt( )方法被调用时会被设置。我们可以使用 isInterrupted( )来测试某个线程当前的 interruptstatus。当前线程的 interrupt status 可以通过调用静态的 Thread.interrupted( )方法清除。

    Scatter/Gather(分散/收集)

    scatter:对于 read 操作而言,从通道读取的数据会按顺序被散布(称为 scatter)到多个缓冲区,将每个缓冲区填满直至通道中的数63据或者缓冲区的最大空间被消耗完。
    gather:对于一个 write 操作而言,数据是从几个缓冲区按顺序抽取(称为 gather)并沿着通道发送的。缓冲区本身并不需要具备这种 gather 的能力(通常它们也没有此能力)。该 gather 过程的效果就好比全部缓冲区的内容被连结起来,并在发送数据前存放到一个大的缓冲区中。
    scatter / gather经常用于需要将传输的数据分开处理的场合,例如传输一个由消息头和消息体组成的消息,你可能会将消息体和消息头分散到不同的buffer中,这样你可以方便的处理消息头和消息体。
    gather代码例如:

    ByteBuffer header = ByteBuffer.allocateDirect (10);
    ByteBuffer body = ByteBuffer.allocateDirect (80);
    ByteBuffer [] buffers = { header, body };
    int bytesRead = channel.read (buffers);

    scatter代码例如:

    ByteBuffer header = ByteBuffer.allocate(128);
    ByteBuffer body = ByteBuffer.allocate(1024);
    //write data into buffers        
    ByteBuffer[] bufferArray = {header, body};
    channel.write(bufferArray);

    使用得当的话, Scatter/Gather 会是一个极其强大的工具。它允许您委托操作系统来完成辛苦活:将读取到的数据分开存放到多个存储桶( bucket)或者将不同的数据区块合并成一个整体。这是一个巨大的成就,因为操作系统已经被高度优化来完成此类工作了。它节省了您来回移动数据的工作,也就避免了缓冲区拷贝和减少了您需要编写、调试的代码数量。既然您基本上通过提供数据容器引用来组合数据,那么按照不同的组合构建多个缓冲区阵列引用,各种数据区块就可以以不同的方式来组合了

    文件通道

    FileChannel 类可以实现常用的 read, write 以及 scatter/gather 操作,同时它也提供了很多专用于文件的新方法。
    FileChannel对象不能直接创建。一个FileChannel实例只能通过在一个打开的file对象( RandomAccessFile、 FileInputStream或 FileOutputStream)上调用getChannel( )方法获取。调用getChannel( )方法会返回一个连接到相同文件的FileChannel对象且该FileChannel对象具有与file对象相同的访问权限,然后您就可以使用该通道对象来利用强大的FileChannel API了
    看个例子,如下:

    public static void main(String[] argv) throws Exception {
            RandomAccessFile raf = new RandomAccessFile("/usr/local/swk/dump.txt","rw");
            FileChannel fc = raf.getChannel();
            ByteBuffer bf = ByteBuffer.allocate(4);
            int byteReads = fc.read(bf);
            while(byteReads !=-1){
                // 转为读模式
                bf.flip();
                while(bf.hasRemaining()){
                    System.out.println(bf.getChar());
                }
                bf.clear();
                byteReads = fc.read(bf);
            }
            raf.close();
        }

    FileChannel 对象是线程安全( thread-safe)的。如果有一个线程已经在执行会影响通道位置或文件大小的操作,那么其他尝试进行此类操作之一的线程必须等待。

    文件锁定

    如果一个线程在某个文件上获得了一个独占锁,然后第二个线程利用一个单独打开的通道来请求该文件的独占锁,那么第二个线程的请求会被批准。但如果这两个线程运行在不同的 Java 虚拟机上,那么第二个线程会阻塞,因为锁最终是由操作系统或文件系统来判优的并且几乎总是在进程级而非线程级上判优。锁都是与一个文件关联的,而不是与单个的文件句柄或通道关联。
    一个 FileLock 对象创建之后即有效,直到它的 release( )方法被调用或它所关联的通道被关闭或Java 虚拟机关闭时才会失效,可以通过调用 isShared( )方法来测试一个锁以判断它是共享的还是独占的。
    我们来看一个writer和两个或更多的 readers 开始,我们来看下不同类型的锁是如何交互的代码实例

    public class LockTest {
    
        private static final int SIZEOF_INT = 4;
        private static final int INDEX_START = 0;
        private static final int INDEX_COUNT = 10;
        private static final int INDEX_SIZE = INDEX_COUNT * SIZEOF_INT;
        private ByteBuffer buffer = ByteBuffer.allocate (INDEX_SIZE);
        private IntBuffer indexBuffer = buffer.asIntBuffer( );
        private Random rand = new Random( );
        public static void main(String[] args) throws Exception{
            boolean writer = false;
            String fileName;
            if (args.length != 2) {
                System.out.println ("Usage: [ -r | -w ] filename");
                return;
            }
            writer = args[0].equals("-w");
            fileName = args[1];
            @SuppressWarnings("resource")
            RandomAccessFile raf = new RandomAccessFile (fileName,
                    (writer) ? "rw" : "r");
            FileChannel fc = raf.getChannel();
            LockTest lockTest = new LockTest();
            if (writer) {
                lockTest.doUpdates (fc);
            } else {
                lockTest.doQueries (fc);
            }
        }
    
        private void doQueries(FileChannel fc) throws Exception {
    
            while (true) {
                println("trying for shared lock...");
                FileLock lock = fc.lock(INDEX_START, INDEX_SIZE, true);
                int reps = rand.nextInt(60) + 20;
                for (int i = 0; i < reps; i++) {
                    int n = rand.nextInt(INDEX_COUNT);
                    int position = INDEX_START + (n * SIZEOF_INT);
                    buffer.clear();
                    fc.read(buffer, position);
                    int value = indexBuffer.get(n);
                    System.out.println("Index entry " + n + "=" + value);
                    // Pretend to be doing some work
                    Thread.sleep(100);
                }
                lock.release();
                println("<sleeping>");
                Thread.sleep(rand.nextInt(3000) + 500);
            }
    
        }
    
        private void doUpdates(FileChannel fc) throws Exception {
            while (true) {
                println("trying for exclusive lock...");
                FileLock lock = fc.lock(INDEX_START, INDEX_SIZE, false);
                updateIndex(fc);
                lock.release();
                System.out.println("<sleeping>");
                Thread.sleep(rand.nextInt(2000) + 500);
            }
        }
    
        private int idxval = 1;
    
        private void updateIndex(FileChannel fc) throws Exception {
            // "indexBuffer" is an int view of "buffer"
            indexBuffer.clear();
            for (int i = 0; i < INDEX_COUNT; i++) {
                idxval++;
                println("Updating index " + i + "=" + idxval);
                indexBuffer.put(idxval);
                // Pretend that this is really hard work
                Thread.sleep(500);
            }
            // leaves position and limit correct for whole buffer
            buffer.clear();
            fc.write(buffer, INDEX_START);
        }
    
        private int lastLineLen = 0;
    
        // Specialized println that repaints the current line
        private void println(String msg) {
            System.out.print("\r ");
            System.out.print(msg);
            for (int i = msg.length(); i < lastLineLen; i++) {
                System.out.print(" ");
            }
            System.out.print("\r");
            System.out.flush();
            lastLineLen = msg.length();
        }
    
    }

    socket通道

    全部 socket 通道类( DatagramChannel、 SocketChannel 和ServerSocketChannel)都是由位于 java.nio.channels.spi 包中的 AbstractSelectableChannel 引申而来。这意味着我们可以用一个 Selector 对象来执行 socket 通道的有条件的选择( readiness selection)。全部 socket 通道类在被实例化时都会创建一个对等 socket 对象。这些是我们所熟悉的来自 java.net 的类( Socket、 ServerSocket和 DatagramSocket),它们已经被更新以识别通道。对等 socket 可以通过调用 socket( )方法从一个通道上获取。
    Socket 通道可以在非阻塞模式下运行,要把一个 socket 通道置于非阻塞模式,我们要依靠所有 socket 通道类的公有超级类:SelectableChannel。下面的方法就是关于通道的阻塞模式的:

    public abstract class SelectableChannel extends AbstractChannel implements Channel
    {
    // This is a partial API listing
    public abstract void configureBlocking (boolean block)
    throws IOException;
    public abstract boolean isBlocking( );
    public abstract Object blockingLock( );
    }

    socketChannel

    Socket 和 SocketChannel 类封装点对点、有序的网络连接,类似于我们所熟知并喜爱的 TCP/IP网络连接。 SocketChannel 扮演客户端发起同一个监听服务器的连接。直到连接成功,它才能收到数据并且只会从连接到的地址接收。每个 SocketChannel 对象创建时都是同一个对等的 java.net.Socket 对象串联的。静态的 open( )方法可以创建一个新的 SocketChannel 对象,而在新创建的 SocketChannel 上调用 socket( )方法能返回它对等的 Socket 对象;在该 Socket 上调用 getChannel( )方法则能返回最初的那个 SocketChannel。
    虽然每个 SocketChannel 对象都会创建一个对等的 Socket 对象,反过来却不成立。直接创建的 Socket 对象不会关联 SocketChannel 对象,它们的getChannel( )方法只返回 null
    新创建的 SocketChannel 虽已打开却是未连接的。在一个未连接的 SocketChannel 对象上尝试一个 I/O 操作会导致 NotYetConnectedException 异常。我们可以通过在通道上直接调用 connect( )方法或在通道关联的 Socket 对象上调用 connect( )来将该 socket 通道连接。一旦一个 socket 通道被连接,它将保持连接状态直到被关闭。您可以通过调用布尔型的 isConnected( )方法来测试某个SocketChannel 当前是否已连接。

    SocketChannel socketChannel =SocketChannel.open (new InetSocketAddress ("somehost", somePort));

    等价于

    SocketChannel socketChannel = SocketChannel.open( );
    socketChannel.connect (new InetSocketAddress ("somehost", somePort));

    在 SocketChannel 上并没有一种 connect( )方法可以让您指定超时( timeout)值,当 connect( )方法在非阻塞模式下被调用时 SocketChannel 提供并发连接:它发起对请求地址的连接并且立即返回值。如果返回值是 true,说明连接立即建立了(这可能是本地环回连接);如果连接不能立即建立, connect( )方法会返回 false 且并发地继续连接建立过程。
    当通道处于中间的连接等待( connection-pending)状态时,您只可以调用 finishConnect( )、isConnectPending( )或 isConnected( )方法。一旦连接建立过程成功完成, isConnected( )将返回 true值

    InetSocketAddress addr = new InetSocketAddress (host, port);
    SocketChannel sc = SocketChannel.open( );
    sc.configureBlocking (false);
    sc.connect (addr);
    while ( ! sc.finishConnect( )) {
    doSomethingElse( );
    }
    doSomethingWithChannel (sc);
    sc.close( );
    

    下面我们看一个管理异步连接的可用代码实例(建立并发连接)

    package com.swk.nio;
    
    import java.net.InetSocketAddress;
    import java.nio.channels.SocketChannel;
    
    /**
     * 建立并发连接
     * 
     * @author fuyuwei 2017年6月25日 上午00:29:12
     */
    public class ConnectAsync {
        public static void main(String[] argv) throws Exception {
            String host = "localhost";
            int port = 80;
            if (argv.length == 2) {
                host = argv[0];
                port = Integer.parseInt(argv[1]);
            }
            InetSocketAddress addr = new InetSocketAddress(host, port);
            SocketChannel sc = SocketChannel.open();
            sc.configureBlocking(false);
            System.out.println("initiating connection");
            sc.connect(addr);
            while (!sc.finishConnect()) {
                doSomethingUseful();
            }
            System.out.println("connection established");
            // Do something with the connected socket
            // The SocketChannel is still nonblocking
            sc.close();
        }
    
        private static void doSomethingUseful() {
            System.out.println("doing something useless");
        }
    }

    如果尝试异步连接失败,那么下次调用 finishConnect( )方法会产生一个适当的经检查的异常以指出问题的性质。通道然后就会被关闭并将不能被连接或再次使用
    connect( )和 finishConnect( )方法是互相同步的,并且只要其中一个操作正在进行,任何读或写的方法调用都会阻塞,即使是在非阻塞模式下。如果此情形下您有疑问或不能承受一个读或写操作在某个通道上阻塞,请用 isConnected( )方法测试一下连接状态。

    管道

    java.nio.channels 包中含有一个名为 Pipe(管道)的类。广义上讲,管道就是一个用来在两个实体之间单向传输数据的导管。Pipe 类创建一对提供环回机制的 Channel 对象。这两个通道的远端是连接起来的,以便任何写在 SinkChannel 对象上的数据都能出现在 SourceChannel 对象上。
    Pipe 实例是通过调用不带参数的 Pipe.open( )工厂方法来创建的。 Pipe 类定义了两个嵌套的通道类来实现管路。这两个类是 Pipe.SourceChannel(管道负责读的一端)和Pipe.SinkChannel(管道负责写的一端)。这两个通道实例是在 Pipe 对象创建的同时被创建的,可以通过在 Pipe 对象上分别调用 source( )和 sink( )方法来取回。管道可以被用来仅在同一个 Java 虚拟机内部传输数据。虽然有更加有效率的方式来在线程之间传输数据,但是使用管道的好处在于封装性。生产者线程和用户线程都能被写道通用的 ChannelAPI 中。根据给定的通道类型,相同的代码可以被用来写数据到一个文件、 socket 或管道。选择器可以被用来检查管道上的数据可用性,如同在 socket 通道上使用那样地简单。这样就可以允许单个用户线程使用一个 Selector 来从多个通道有效地收集数据,并可任意结合网络连接或本地工作线程使用。因此,这些对于可伸缩性、冗余度以及可复用性来说无疑都是意义重大的。
    下面看个管道的代码实例

    package com.swk.nio;
    
    import java.nio.ByteBuffer;
    import java.nio.channels.Channels;
    import java.nio.channels.Pipe;
    import java.nio.channels.ReadableByteChannel;
    import java.nio.channels.WritableByteChannel;
    import java.util.Random;
    
    /**
     * 工作线程对一个管道进行写操作
     * 
     * @author fuyuwei 2017年6月25日 上午12:41:52
     */
    public class PipeTest {
    
        public static void main(String[] argv) throws Exception {
            // Wrap a channel around stdout
            WritableByteChannel out = Channels.newChannel(System.out);
            // Start worker and get read end of channel
            ReadableByteChannel workerChannel = startWorker(10);
            ByteBuffer buffer = ByteBuffer.allocate(100);
            while (workerChannel.read(buffer) >= 0) {
                buffer.flip();
                out.write(buffer);
                buffer.clear();
            }
        }
    
        // This method could return a SocketChannel or
        // FileChannel instance just as easily
        private static ReadableByteChannel startWorker(int reps) throws Exception {
            Pipe pipe = Pipe.open();
            Worker worker = new Worker(pipe.sink(), reps);
            worker.start();
            return (pipe.source());
        }
    
        // -----------------------------------------------------------------
        /**
         * A worker thread object which writes data down a channel. Note: this
         * object knows nothing about Pipe, uses only a generic WritableByteChannel.
         */
        private static class Worker extends Thread {
            WritableByteChannel channel;
            private int reps;
    
            Worker(WritableByteChannel channel, int reps) {
                this.channel = channel;
                this.reps = reps;
            }
    
            // Thread execution begins here
            public void run() {
                ByteBuffer buffer = ByteBuffer.allocate(100);
                try {
                    for (int i = 0; i < this.reps; i++) {
                        doSomeWork(buffer);
                        // channel may not take it all at once
                        while (channel.write(buffer) > 0) {
                            // empty
                        }
                    }
                    this.channel.close();
                } catch (Exception e) {
                    // easy way out; this is demo code
                    e.printStackTrace();
                }
            }
    
            private String[] products = { "No good deed goes unpunished",
                    "To be, or what?", "No matter where you go, there you are",
                    "Just say \"Yo\"", "My karma ran over my dogma" };
            private Random rand = new Random();
    
            private void doSomeWork(ByteBuffer buffer) {
                int product = rand.nextInt(products.length);
                buffer.clear();
                buffer.put(products[product].getBytes());
                buffer.put("\r\n".getBytes());
                buffer.flip();
            }
        }
    }
    展开全文
  • 针对Faster-RCNN等卷积网络图片输入通道数的问题,给出一种解决方法: 一般的卷积网络都是rgb三个通道,但这限制了单通道灰度图的检测,这里先给出一种比较笨拙但能解决问题的办法:强行给图片赋予三个通道出来: ...
  • 服务器双通道与单通道的差别

    千次阅读 2017-09-22 15:14:16
    【IT168 评测】随着...内存厂商只要提高内存的运行频率,就可以增加带宽,但是由于受到晶体管本身的特性和制造技术的制约,内存频率不可能无限制地提升,所以在全新的内存研发出来之前,多通道内存技术就成了一种
  • 1.输入通道个数 = 卷积核通道个数 2.卷积核个数 = 输出通道个数
  • (9)隐蔽通道重点知识复习笔记

    千次阅读 2017-12-14 10:56:26
    隐蔽通道
  • 关于光纤通道

    千次阅读 2005-04-22 10:08:00
    光纤通道标准是由T11标准委员会(美国国家信息技术标准化委员会下属的技术委员会)制定的。定义光纤通道是一种在计算机和海量存储器上广泛应用的高速串行接口。与SCSI接口相比,光纤通道兼有I/O通道和局域网的特性,...
  • 通道图片的卷积

    千次阅读 2019-10-26 15:33:33
    一、多通道(channels)图片的卷积 网上很多资料都是单通道的卷积,很容易理解。但多通道的卷积更普遍,理解较复杂,需要单独提一下。彩色图像,一般都是RGB三个通道(channel)的,因此输入数据的维度一般有三个:...
  • 中断、DMA、通道

    千次阅读 2008-12-01 10:31:00
    一、轮询方式 对I/O设备的程序轮询的方式,是早期的计算机系统对I/O设备的一种管理方式。它定时对各种设备轮流询问一遍有无处理... 当然,再快的处理机,能处理的输入输出设备的数量也是有一定限度的。而且,程序轮询
  • 扩容解决方案:状态通道

    万次阅读 2019-05-13 18:19:22
    在以太坊中,我们定义扩容为随着用户(dApp)数量提高,提高主网性能(吞吐量,延迟)的能力,并且不会对用户体验(gas 价格,转账时间)造成什么影响。随着网络中增加的东西变多,网络架构一定要能够适应新的需求,...
  • 我们新买的海康威视的摄像头在通道名称处,系统会自动命名为摄像头1、摄像头2、摄像头3等等:如图所示 但是在我们进行海康威视摄像头二次开发或者正常使用的过程中,通常不希望以这样的名称来命名我们的摄像头 ...
  • Zookeeper隐藏通道和羊群效应

    千次阅读 2018-07-10 09:03:27
    隐藏通道 ZooKeeper客户端总是会观察到相同的更新顺序,即使它们连接到不同的服务端上。但是客户端可能是在不同时间观察到了更新,如果他们还在ZooKeeper以外通信,这种差异就会更加明显。让我们考虑以下场景:  ...
  • 通道  内存的工作由主板的北桥芯片组控制.以前的老主板只有一个内存控制器,所以无论插多少内存上去都只有单通道,就象高速路结束时只有一个收费站一样,只有一个出口可以放车子出去.  后来的主板有了这...
  • 增强版唐奇安通道策略

    千次阅读 2019-12-25 11:39:18
    前言 ...但时过境迁,现在的市场环境已经发生了很大的变化,这导致唐奇安通道策略变得低效,那么今天我们试着改进,看看增强版的唐奇安通道策略效果如何。 唐奇安通道简介 原始的唐奇安通道(Donc...
  • three后期处理与多通道渲染

    千次阅读 2018-04-19 09:29:04
    1)创建一个EffectComposer(效果组合器)对象,然后在该对象上添加后期处理通道。 2)配置该对象,使它可以渲染我们的场景,并应用额外的后期处理步骤。 3)在render循环中,使用EffectComposer渲染场景、应用...
  • “互联网+”背景下的消费模式完全不同于传统消费模式,对商品生产、市场流通、经营销售都产生了巨大的影响,合成了消费模式的新常态。 数字货币是在全世界已被互联网整合拉近成为“地球村”基础上的金融,是甲投资...
  • 极光厂商通道集成指南

    千次阅读 2019-03-26 18:53:46
    极光厂商通道集成指南 小米集成指南 1、使用JCenter自动化集成步骤 确认AndroidStudio的Project根目录的主gradle中配置了jcenter支持。(新建project默认配置就支持) buildscript { repositories { ...
  • 之前完成了规则通道DMA的数据传输了,不过平时在使用ADC的时候可能就会遇到很多情况,不可能就这样简单的按规则通道来采样,DMA存储,使用数据的;可能有时候会需要立刻采样,那样我们就需要利用到注入通道了。文档...
  • FBX顶点变形目标通道

    千次阅读 2017-04-25 23:15:16
    FBX顶点变形目标通道 本页面的内容: 概述命名设置顶点变形目标导出顶点变形目标导入顶点变形目标 概述 顶点变形目标是已经以某种方式发生变形的特定网格物体的顶点位置的快照。比如,您可以取...
  • 最近在做一个图像分类的项目,由于性能比较差,因此需要尝试将彩色图转为灰度图进行训练,从而屏蔽掉颜色对分类结果的影响而着重关注纹理、结构等信息。由于样本数量较少,只有几百张的样子,如果...
  • 通道可以是单向的也可以是双向的,一个通道类可以实现ReadableByteChannel接口的read()方法,也可以实现WriteableByteChannel接口的write()方法,只要实现其中任一方法,通道就是单向的,实现两个接口为双向。...
  • ---------------------- android培训、java培训、期待与您交流! ---------------------- ...1.通道基础 ...1.1 打开通道 ...那么相应地有两种类型的通道,它们是文件(file)通道和套接字(socket)通道
  • 双均线通道过滤交易系统

    千次阅读 2018-12-31 15:25:58
    本策略简介 传统的双均线交易系统是通过快速均线与慢速均线的交叉来捕捉趋势;当快速均线上穿慢速均线的时候,出现买入信号,指示有一波上涨趋势;...为了将假趋势信号过滤掉,可以将双均线与通道结合起...
  • Oracle RMAN(Recovery Manager) – 通道分配

    千次阅读 2016-03-13 10:40:48
    通道(Channel)在RMAN的工作中当着非常重要的角色,所有的备份和恢复都是由通道去完成的。 工作原理 所谓通道,是指由服务器进程发起并控制的目标数据库的文件与物理备份设备之间的字节流。 字节流的方向取决于...
  • 接入友盟厂商push通道遇到的坑

    千次阅读 2020-02-26 19:05:15
    使用友盟厂商通道并且保留了原友盟通道时遇到的各种问题,以及排查出的问题原因。
  • 快速最优通道布线算法(详细)

    万次阅读 2015-06-25 23:30:38
    这种串行布线方式速度甚慢且通常不可能获得理想结果,原因就是先布的线只能根据本身的需要确定其“最优路径”,这样就有可能布在不恰当的位置,妨碍以致完全阻塞某些后布的线,从而影响整个布线的质量和布线率。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 73,262
精华内容 29,304
关键字:

影响通道的数量的是