精华内容
下载资源
问答
  •  读完这一章,我们基本上可以了解到Netty所有重要的组件,对Netty有一个全面的认识,这对下一步深入学习Netty是十分重要的,而学完这一章,我们其实已经可以用Netty解决一些常规的问题了。 一、先纵览一下...

    http://www.tuicool.com/articles/mEJvYb


       读完这一章,我们基本上可以了解到Netty所有重要的组件,对Netty有一个全面的认识,这对下一步深入学习Netty是十分重要的,而学完这一章,我们其实已经可以用Netty解决一些常规的问题了。


    一、先纵览一下Netty,看看Netty都有哪些组件?

         为了更好的理解和进一步深入Netty,我们先总体认识一下Netty用到的组件及它们在整个Netty架构中是怎么协调工作的。Netty应用中必不可少的组件:
    • Bootstrap or ServerBootstrap
    • EventLoop
    • EventLoopGroup
    • ChannelPipeline
    • Channel
    • Future or ChannelFuture
    • ChannelInitializer
    • ChannelHandler

         Bootstrap,一个Netty应用通常由一个Bootstrap开始,它主要作用是配置整个Netty程序,串联起各个组件。

         Handler,为了支持各种协议和处理数据的方式,便诞生了Handler组件。Handler主要用来处理各种事件,这里的事件很广泛,比如可以是连接、数据接收、异常、数据转换等。

         ChannelInboundHandler,一个最常用的Handler。这个Handler的作用就是处理接收到数据时的事件,也就是说,我们的业务逻辑一般就是写在这个Handler里面的,ChannelInboundHandler就是用来处理我们的核心业务逻辑。

         ChannelInitializer,当一个链接建立时,我们需要知道怎么来接收或者发送数据,当然,我们有各种各样的Handler实现来处理它,那么ChannelInitializer便是用来配置这些Handler,它会提供一个ChannelPipeline,并把Handler加入到ChannelPipeline。

         ChannelPipeline,一个Netty应用基于ChannelPipeline机制,这种机制需要依赖于EventLoop和EventLoopGroup,因为它们三个都和事件或者事件处理相关。

         EventLoops的目的是为Channel处理IO操作,一个EventLoop可以为多个Channel服务。

         EventLoopGroup会包含多个EventLoop。

         Channel代表了一个Socket链接,或者其它和IO操作相关的组件,它和EventLoop一起用来参与IO处理。

         Future,在Netty中所有的IO操作都是异步的,因此,你不能立刻得知消息是否被正确处理,但是我们可以过一会等它执行完成或者直接注册一个监听,具体的实现就是通过Future和ChannelFutures,他们可以注册一个监听,当操作执行成功或失败时监听会自动触发。总之,所有的操作都会返回一个ChannelFuture。


    二、Netty是如何处理连接请求和业务逻辑的呢?-- Channels、Events 和 IO

         Netty是一个非阻塞的、事件驱动的、网络编程框架。当然,我们很容易理解Netty会用线程来处理IO事件,对于熟悉多线程编程的人来说,你或许会想到如何同步你的代码,但是Netty不需要我们考虑这些,具体是这样:

          一个Channel会对应一个EventLoop,而一个EventLoop会对应着一个线程,也就是说,仅有一个线程在负责一个Channel的IO操作。

         关于这些名词之间的关系,可以见下图:

         
          

         如图所示:当一个连接到达,Netty会注册一个channel,然后EventLoopGroup会分配一个EventLoop绑定到这个channel,在这个channel的整个生命周期过程中,都会由绑定的这个EventLoop来为它服务,而这个EventLoop就是一个线程。

         说到这里,那么EventLoops和EventLoopGroups关系是如何的呢?我们前面说过一个EventLoopGroup包含多个Eventloop,但是我们看一下下面这幅图,这幅图是一个继承树,从这幅图中我们可以看出,EventLoop其实继承自EventloopGroup,也就是说,在某些情况下,我们可以把一个EventLoopGroup当做一个EventLoop来用。



    三、我们来看看如何配置一个Netty应用?-- BootsStrapping

         我们利用BootsStrapping来配置netty 应用,它有两种类型,一种用于Client端:BootsStrap,另一种用于Server端:ServerBootstrap,要想区别如何使用它们,你仅需要记住一个用在Client端,一个用在Server端。下面我们来详细介绍一下这两种类型的区别:

         1.第一个最明显的区别是,ServerBootstrap用于Server端,通过调用bind()方法来绑定到一个端口监听连接;Bootstrap用于Client端,需要调用connect()方法来连接服务器端,但我们也可以通过调用bind()方法返回的ChannelFuture中获取Channel去connect服务器端。

         2.客户端的Bootstrap一般用一个EventLoopGroup,而服务器端的ServerBootstrap会用到两个(这两个也可以是同一个实例)。为何服务器端要用到两个EventLoopGroup呢?这么设计有明显的好处,如果一个ServerBootstrap有两个EventLoopGroup,那么就可以把第一个EventLoopGroup用来专门负责绑定到端口监听连接事件,而把第二个EventLoopGroup用来处理每个接收到的连接,下面我们用一幅图来展现一下这种模式:

             

         PS: 如果仅由一个EventLoopGroup处理所有请求和连接的话,在并发量很大的情况下,这个EventLoopGroup有可能会忙于处理已经接收到的连接而不能及时处理新的连接请求,用两个的话,会有专门的线程来处理连接请求,不会导致请求超时的情况,大大提高了并发处理能力。

          我们知道一个Channel需要由一个EventLoop来绑定,而且两者一旦绑定就不会再改变。一般情况下一个EventLoopGroup中的EventLoop数量会少于Channel数量,那么就很有可能出现一个多个Channel公用一个EventLoop的情况,这就意味着如果一个Channel中的EventLoop很忙的话,会影响到这个Eventloop对其它Channel的处理,这也就是为什么我们不能阻塞EventLoop的原因。

         当然,我们的Server也可以只用一个EventLoopGroup,由一个实例来处理连接请求和IO事件,请看下面这幅图:


          

     

    四、我们看看Netty是如何处理数据的?-- Netty核心ChannelHandler

         下面我们来看一下netty中是怎样处理数据的,回想一下我们前面讲到的Handler,对了,就是它。说到Handler我们就不得不提ChannelPipeline,ChannelPipeline负责安排Handler的顺序及其执行,下面我们就来详细介绍一下他们:

     ChannelPipeline and handlers

         我们的应用程序中用到的最多的应该就是ChannelHandler,我们可以这么想象,数据在一个ChannelPipeline中流动,而ChannelHandler便是其中的一个个的小阀门,这些数据都会经过每一个ChannelHandler并且被它处理。这里有一个公共接口ChannelHandler:


         

         从上图中我们可以看到,ChannelHandler有两个子类ChannelInboundHandler和ChannelOutboundHandler,这两个类对应了两个数据流向,如果数据是从外部流入我们的应用程序,我们就看做是inbound,相反便是outbound。其实ChannelHandler和Servlet有些类似,一个ChannelHandler处理完接收到的数据会传给下一个Handler,或者什么不处理,直接传递给下一个。下面我们看一下ChannelPipeline是如何安排ChannelHandler的:


         

         从上图中我们可以看到,一个ChannelPipeline可以把两种Handler(ChannelInboundHandler和ChannelOutboundHandler)混合在一起,当一个数据流进入ChannelPipeline时,它会从ChannelPipeline头部开始传给第一个ChannelInboundHandler,当第一个处理完后再传给下一个,一直传递到管道的尾部。与之相对应的是,当数据被写出时,它会从管道的尾部开始,先经过管道尾部的“最后”一个ChannelOutboundHandler,当它处理完成后会传递给前一个ChannelOutboundHandler。

    数据在各个Handler之间传递,这需要调用方法中传递的ChanneHandlerContext来操作, 在netty的API中提供了两个基类分ChannelOutboundHandlerAdapter和ChannelOutboundHandlerAdapter,他们仅仅实现了调用ChanneHandlerContext来把消息传递给下一个Handler,因为我们只关心处理数据,因此我们的程序中可以继承这两个基类来帮助我们做这些,而我们仅需实现处理数据的部分即可。

         我们知道InboundHandler和OutboundHandler在ChannelPipeline中是混合在一起的,那么它们如何区分彼此呢?其实很容易,因为它们各自实现的是不同的接口,对于inbound event,Netty会自动跳过OutboundHandler,相反若是outbound event,ChannelInboundHandler会被忽略掉。

         当一个ChannelHandler被加入到ChannelPipeline中时,它便会获得一个ChannelHandlerContext的引用,而ChannelHandlerContext可以用来读写Netty中的数据流。因此,现在可以有两种方式来发送数据,一种是把数据直接写入Channel,一种是把数据写入ChannelHandlerContext,它们的区别是写入Channel的话,数据流会从Channel的头开始传递,而如果写入ChannelHandlerContext的话,数据流会流入管道中的下一个Handler。   

    五、我们最关心的部分,如何处理我们的业务逻辑? -- Encoders, Decoders and Domain Logic

         Netty中会有很多Handler,具体是哪种Handler还要看它们继承的是InboundAdapter还是OutboundAdapter。当然,Netty中还提供了一些列的Adapter来帮助我们简化开发,我们知道在Channelpipeline中每一个Handler都负责把Event传递给下一个Handler,如果有了这些辅助Adapter,这些额外的工作都可自动完成,我们只需覆盖实现我们真正关心的部分即可。此外,还有一些Adapter会提供一些额外的功能,比如编码和解码。那么下面我们就来看一下其中的三种常用的ChannelHandler:

    Encoders和Decoders

         因为我们在网络传输时只能传输字节流,因此,才发送数据之前,我们必须把我们的message型转换为bytes,与之对应,我们在接收数据后,必须把接收到的bytes再转换成message。我们把bytes to message这个过程称作Decode(解码成我们可以理解的),把message to bytes这个过程成为Encode。

         Netty中提供了很多现成的编码/解码器,我们一般从他们的名字中便可知道他们的用途,如ByteToMessageDecoder、MessageToByteEncoder,如专门用来处理Google Protobuf协议的ProtobufEncoder、 ProtobufDecoder。

         我们前面说过,具体是哪种Handler就要看它们继承的是InboundAdapter还是OutboundAdapter,对于Decoders,很容易便可以知道它是继承自ChannelInboundHandlerAdapter或 ChannelInboundHandler,因为解码的意思是把ChannelPipeline传入的bytes解码成我们可以理解的message(即Java Object),而ChannelInboundHandler正是处理Inbound Event,而Inbound Event中传入的正是字节流。Decoder会覆盖其中的“ChannelRead()”方法,在这个方法中来调用具体的decode方法解码传递过来的字节流,然后通过调用ChannelHandlerContext.fireChannelRead(decodedMessage)方法把编码好的Message传递给下一个Handler。与之类似,Encoder就不必多少了。

    Domain Logic

         其实我们最最关心的事情就是如何处理接收到的解码后的数据,我们真正的业务逻辑便是处理接收到的数据。Netty提供了一个最常用的基类SimpleChannelInboundHandler<T>,其中T就是这个Handler处理的数据的类型(上一个Handler已经替我们解码好了),消息到达这个Handler时,Netty会自动调用这个Handler中的channelRead0(ChannelHandlerContext,T)方法,T是传递过来的数据对象,在这个方法中我们便可以任意写我们的业务逻辑了。


    展开全文
  • 读完这一章,我们基本上可以了解到Netty所有重要的组件,对Netty有一个全面的认识,这对下一步深入学习Netty是十分重要的,而学完这一章,我们其实已经可以用Netty解决一些常规的问题了。一、先纵览一下Netty,看看...

    读完这一章,我们基本上可以了解到Netty所有重要的组件,对Netty有一个全面的认识,这对下一步深入学习Netty是十分重要的,而学完这一章,我们其实已经可以用Netty解决一些常规的问题了。一、先纵览一下Netty,看看Netty都有哪些组件? 为了更好的理解和进一步深入Netty,我们先总体认识一下Netty用到的组件及它们在整个Netty架构中是怎么协调工作的。Netty应用中必不可少的组件:Bootstrap or ServerBootstrapEventLoopEventLoopGroupChannelPipelineChannelFuture or ChannelFutureChannelInitializerChannelHandler Bootstrap,一个Netty应用通常由一个Bootstrap开始,它主要作用是配置整个Netty程序,串联起各个组件。 Handler,为了支持各种协议和处理数据的方式,便诞生了Handler组件。Handler主要用来处理各种事件,这里的事件很广泛,比如可以是连接、数据接收、异常、数据转换等。 ChannelInboundHandler,一个最常用的Handler。这个Handler的作用就是处理接收到数据时的事件,也就是说,我们的业务逻辑一般就是写在这个Handler里面的,ChannelInboundHandler就是用来处理我们的核心业务逻辑。 ChannelInitializer,当一个链接建立时,我们需要知道怎么来接收或者发送数据,当然,我们有各种各样的Handler实现来处理它,那么ChannelInitializer便是用来配置这些Handler,它会提供一个ChannelPipeline,并把Handler加入到ChannelPipeline。 ChannelPipeline,一个Netty应用基于ChannelPipeline机制,这种机制需要依赖于EventLoop和EventLoopGroup,因为它们三个都和事件或者事件处理相关。 EventLoops的目的是为Channel处理IO操作,一个EventLoop可以为多个Channel服务。 EventLoopGroup会包含多个EventLoop。 Channel代表了一个Socket链接,或者其它和IO操作相关的组件,它和EventLoop一起用来参与IO处理。 Future,在Netty中所有的IO操作都是异步的,因此,你不能立刻得知消息是否被正确处理,但是我们可以过一会等它执行完成或者直接注册一个监听,具体的实现就是通过Future和ChannelFutures,他们可以注册一个监听,当操作执行成功或失败时监听会自动触发。总之,所有的操作都会返回一个ChannelFuture。二、Netty是如何处理连接请求和业务逻辑的呢?-- Channels、Events 和 IO Netty是一个非阻塞的、事件驱动的、网络编程框架。当然,我们很容易理解Netty会用线程来处理IO事件,对于熟悉多线程编程的人来说,你或许会想到如何同步你的代码,但是Netty不需要我们考虑这些,具体是这样: 一个Channel会对应一个EventLoop,而一个EventLoop会对应着一个线程,也就是说,仅有一个线程在负责一个Channel的IO操作。 关于这些名词之间的关系,可以见下图: 如图所示:当一个连接到达,Netty会注册一个channel,然后EventLoopGroup会分配一个EventLoop绑定到这个channel,在这个channel的整个生命周期过程中,都会由绑定的这个EventLoop来为它服务,而这个EventLoop就是一个线程。 说到这里,那么EventLoops和EventLoopGroups关系是如何的呢?我们前面说过一个EventLoopGroup包含多个Eventloop,但是我们看一下下面这幅图,这幅图是一个继承树,从这幅图中我们可以看出,EventLoop其实继承自EventloopGroup,也就是说,在某些情况下,我们可以把一个EventLoopGroup当做一个EventLoop来用。三、我们来看看如何配置一个Netty应用?-- BootsStrapping 我们利用BootsStrapping来配置netty 应用,它有两种类型,一种用于Client端:BootsStrap,另一种用于Server端:ServerBootstrap,要想区别如何使用它们,你仅需要记住一个用在Client端,一个用在Server端。下面我们来详细介绍一下这两种类型的区别: 1.第一个最明显的区别是,ServerBootstrap用于Server端,通过调用bind()方法来绑定到一个端口监听连接;Bootstrap用于Client端,需要调用connect()方法来连接服务器端,但我们也可以通过调用bind()方法返回的ChannelFuture中获取Channel去connect服务器端。 2.客户端的Bootstrap一般用一个EventLoopGroup,而服务器端的ServerBootstrap会用到两个(这两个也可以是同一个实例)。为何服务器端要用到两个EventLoopGroup呢?这么设计有明显的好处,如果一个ServerBootstrap有两个EventLoopGroup,那么就可以把第一个EventLoopGroup用来专门负责绑定到端口监听连接事件,而把第二个EventLoopGroup用来处理每个接收到的连接,下面我们用一幅图来展现一下这种模式: PS: 如果仅由一个EventLoopGroup处理所有请求和连接的话,在并发量很大的情况下,这个EventLoopGroup有可能会忙于处理已经接收到的连接而不能及时处理新的连接请求,用两个的话,会有专门的线程来处理连接请求,不会导致请求超时的情况,大大提高了并发处理能力。 我们知道一个Channel需要由一个EventLoop来绑定,而且两者一旦绑定就不会再改变。一般情况下一个EventLoopGroup中的EventLoop数量会少于Channel数量,那么就很有可能出现一个多个Channel公用一个EventLoop的情况,这就意味着如果一个Channel中的EventLoop很忙的话,会影响到这个Eventloop对其它Channel的处理,这也就是为什么我们不能阻塞EventLoop的原因。 当然,我们的Server也可以只用一个EventLoopGroup,由一个实例来处理连接请求和IO事件,请看下面这幅图: 四、我们看看Netty是如何处理数据的?-- Netty核心ChannelHandler 下面我们来看一下netty中是怎样处理数据的,回想一下我们前面讲到的Handler,对了,就是它。说到Handler我们就不得不提ChannelPipeline,ChannelPipeline负责安排Handler的顺序及其执行,下面我们就来详细介绍一下他们: ChannelPipeline and handlers 我们的应用程序中用到的最多的应该就是ChannelHandler,我们可以这么想象,数据在一个ChannelPipeline中流动,而ChannelHandler便是其中的一个个的小阀门,这些数据都会经过每一个ChannelHandler并且被它处理。这里有一个公共接口ChannelHandler: 从上图中我们可以看到,ChannelHandler有两个子类ChannelInboundHandler和ChannelOutboundHandler,这两个类对应了两个数据流向,如果数据是从外部流入我们的应用程序,我们就看做是inbound,相反便是outbound。其实ChannelHandler和Servlet有些类似,一个ChannelHandler处理完接收到的数据会传给下一个Handler,或者什么不处理,直接传递给下一个。下面我们看一下ChannelPipeline是如何安排ChannelHandler的: 从上图中我们可以看到,一个ChannelPipeline可以把两种Handler(ChannelInboundHandler和ChannelOutboundHandler)混合在一起,当一个数据流进入ChannelPipeline时,它会从ChannelPipeline头部开始传给第一个ChannelInboundHandler,当第一个处理完后再传给下一个,一直传递到管道的尾部。与之相对应的是,当数据被写出时,它会从管道的尾部开始,先经过管道尾部的“最后”一个ChannelOutboundHandler,当它处理完成后会传递给前一个ChannelOutboundHandler。数据在各个Handler之间传递,这需要调用方法中传递的ChanneHandlerContext来操作, 在netty的API中提供了两个基类分ChannelOutboundHandlerAdapter和ChannelOutboundHandlerAdapter,他们仅仅实现了调用ChanneHandlerContext来把消息传递给下一个Handler,因为我们只关心处理数据,因此我们的程序中可以继承这两个基类来帮助我们做这些,而我们仅需实现处理数据的部分即可。 我们知道InboundHandler和OutboundHandler在ChannelPipeline中是混合在一起的,那么它们如何区分彼此呢?其实很容易,因为它们各自实现的是不同的接口,对于inbound event,Netty会自动跳过OutboundHandler,相反若是outbound event,ChannelInboundHandler会被忽略掉。 当一个ChannelHandler被加入到ChannelPipeline中时,它便会获得一个ChannelHandlerContext的引用,而ChannelHandlerContext可以用来读写Netty中的数据流。因此,现在可以有两种方式来发送数据,一种是把数据直接写入Channel,一种是把数据写入ChannelHandlerContext,它们的区别是写入Channel的话,数据流会从Channel的头开始传递,而如果写入ChannelHandlerContext的话,数据流会流入管道中的下一个Handler。 五、我们最关心的部分,如何处理我们的业务逻辑? -- Encoders, Decoders and Domain Logic Netty中会有很多Handler,具体是哪种Handler还要看它们继承的是InboundAdapter还是OutboundAdapter。当然,Netty中还提供了一些列的Adapter来帮助我们简化开发,我们知道在Channelpipeline中每一个Handler都负责把Event传递给下一个Handler,如果有了这些辅助Adapter,这些额外的工作都可自动完成,我们只需覆盖实现我们真正关心的部分即可。此外,还有一些Adapter会提供一些额外的功能,比如编码和解码。那么下面我们就来看一下其中的三种常用的ChannelHandler:Encoders和Decoders 因为我们在网络传输时只能传输字节流,因此,才发送数据之前,我们必须把我们的message型转换为bytes,与之对应,我们在接收数据后,必须把接收到的bytes再转换成message。我们把bytes to message这个过程称作Decode(解码成我们可以理解的),把message to bytes这个过程成为Encode。 Netty中提供了很多现成的编码/解码器,我们一般从他们的名字中便可知道他们的用途,如ByteToMessageDecoder、MessageToByteEncoder,如专门用来处理Google Protobuf协议的ProtobufEncoder、 ProtobufDecoder。 我们前面说过,具体是哪种Handler就要看它们继承的是InboundAdapter还是OutboundAdapter,对于Decoders,很容易便可以知道它是继承自ChannelInboundHandlerAdapter或 ChannelInboundHandler,因为解码的意思是把ChannelPipeline传入的bytes解码成我们可以理解的message(即Java Object),而ChannelInboundHandler正是处理Inbound Event,而Inbound Event中传入的正是字节流。Decoder会覆盖其中的“ChannelRead()”方法,在这个方法中来调用具体的decode方法解码传递过来的字节流,然后通过调用ChannelHandlerContext.fireChannelRead(decodedMessage)方法把编码好的Message传递给下一个Handler。与之类似,Encoder就不必多少了。Domain Logic 其实我们最最关心的事情就是如何处理接收到的解码后的数据,我们真正的业务逻辑便是处理接收到的数据。Netty提供了一个最常用的基类SimpleChannelInboundHandler,其中T就是这个Handler处理的数据的类型(上一个Handler已经替我们解码好了),消息到达这个Handler时,Netty会自动调用这个Handler中的channelRead0(ChannelHandlerContext,T)方法,T是传递过来的数据对象,在这个方法中我们便可以任意写我们的业务逻辑了。



    原文链接:http://blog.csdn.net/suifeng3051/article/details/28861883

    展开全文
  • 如何思考,以及如何审视你思考问题的思维。 悖论:领导就是不服气他人发号施令的那个人嘛。 -- 哈哈 真正有影响的行为是。。。 奖励/惩罚模型容易忽略自身和他人的价值,使得负面情绪和信息充斥。全面模型,系统化...

      大师温伯格的作品,精品。要反复阅读,原文与译文总有些差异,要细细琢磨和研读。

      看似教你如何成为领导,倒不如说是教你如何管理和领导自己,以己及人成为真正的领导者。
      技术领导者,技术二字给领导增加了一层不同的色彩,技术人员的特性使其领导方式与其它行业又有所区别。
      万变不离其宗,核心主题依然不变:解决问题的领导的全部目标是创造一个环境,使其中每个人都能解决问题,做出决策,执行这些决策,他不需亲自解决问题,做出决策,再执行。
      浅记于此,待不断深入学习、实践、理解、应用。


      >> 译者:
      如果需要不断改进自己,就必须需要不断观察和审视关于自己的一切,包括习焉不察的坚持。(习焉不察:经常接触某种事物,反而觉察不到其中存在的问题。)
      还有一些东西我不在乎,却是某个人群特别在意的,考虑到其它人的感受,以后还是要多加小心为好。
      单纯靠技术是不能“一俊遮百丑”的。
      想要改变,尤其是自我改变,通常不会像上级布置的任务那样,有明确的压力和期限,所以改变也停留在“想”而已。缺乏行动力。
      第一步是承认自己其实不想实践这些道理。
      既然无法挽回,重新来过就是了。
      不要空想,不要慨叹,而是按部就班地捡起自己的身份证。

      >> 温伯格:
      领导力,就是创造这样一个环境,每个人都能在其中发挥出更多的能力。领导力就是催生其他人身上的创造力和生产力。
      成为领导不是靠运气,而靠投入。
      创新型技术领导:理解差距题、管理思维、保证质量
      解决问题的领导都有一个共同点:他们都相信,总有最好的办法。
      改变的过程通常是牵一发而动全身的,永远不可能一次只改变一小点。 -- 系统化思维?那么改变是大刀阔斧,还是积少成多,从量变到质变。
      领导力是一个培充的过程,而不是监管他人的生活。
      转变是困难的,迷执。
      如何思考,以及如何审视你思考问题的思维。
      悖论:领导就是不服气他人发号施令的那个人嘛。 -- 哈哈
      真正有影响的行为是。。。
      奖励/惩罚模型容易忽略自身和他人的价值,使得负面情绪和信息充斥。全面模型,系统化思维虽能充分理解现状从而选择,但事实是行动第一,因此必须接受可能出现的错误。 -- 在行动中学习和调整?
      你是在现在的环境中学习,还是自我重复。
      你会有自己喜欢的领导方式,不需要自我否定,不是放弃原来的行为,而是增添新的行为。
      工作进行一段之后,能更好地理解某些需求的意义时,回头看看规范。
      管理思维:为团队贡献一个明智的想法,鼓励借鉴有用的想法,完善团队中其他人提出的想法,在团队希望完善的相法面前,放弃自己的想法:不要放弃并非每个人都懂的想法,顶住时间压力,在其他人解释他们的想法时要耐心听取,尝试其提出的想法,为了让想法不断涌现出来不要太是否定同事的想法(否定是一回事,轻率的否定是另一回事);如果必须批评一个想法,务必明确,批评的对象是想法而不是人;在给出想法之前,要试一试;如果时间和人力不够,就别费力去寻求新想法,维持现状就好;如果之前成功的想法不能适应新的形象,要鼓励团队放弃它;如果先前放弃的想法对问题的某个部分有价值,要重新采纳。
      如果你没有解决要解决的问题,其它问题都毫无意义。
      领导就是驾驭变化的人,领导还要把握自身的变化。
      为了成长,你必须离开现有的可靠支撑,放弃已经熟练掌握的策略,甚至可能跌入低谷。如果不放弃已经熟练的策略,就有可能稳步进展,但是永远不会脱离某个稳定阶段。
      元学习,metalearning。掌握通用的技术。
      重复一遍,当领导,不一定要有个头衔。
      创新的三大障碍:看不到自己(不能从旁观者的角度认识自己);没问题综合症(No-Problem syndrome, NPS,未能完全理解就轻率做出决定给出解决方案);维一办法信念(中心教条思想)。看不到自己,看不到自己的行为,所以没有机会变化;没问题综合症,欺骗自己,以为申就知道所有问题的答案;相信经院心理学的中心教条,看不见其它办法,即使你不需要他人帮助就能找到这些办法。
      加深自我了解的工具:每天花五分钟写日记。
      任何实际问题都存在不止一个办法,只是目前还没有人知道。
      因为我会花大量的工夫来证明自己的想法是正确的,甚至都不会听取他们的想法。
      缺乏自我认识,意味着我们从不会注意到自己的错误,所以我们不能发现错误,把坏事变成好事。迷信自己的智力,意味着我们永远不会想到要代签别人的想法,所以我们不能从偷窃创意中受益。相信每个问题有且令有一个答案,就会认为我把想法合并起来很愚蠢,所以当然不用考虑综合。
      重要的不是事情,而是你对事情的态度。
      如果有人的目的并不仅仅在于完成任务--他们还希望获得权力、金钱和声望,整个过程就更为复杂。
      你能做的,会让世界发生变化的事情。
      激励的第一大障碍是各种各样的盲目。独行侠成为领导的第一大障碍就是忽视周围人的反应。
      你可以花时间看的更清楚,听的更清楚。
      花更多精力关注他们问题的办法之一就是直面自己的问题。尝试找到我们疯狂举止的原因。
      如果你不能提供什么实质内容,却要假装有内容,那么无论你多么关心别人,都会吸引住他们。
      领导往往会高估自己工作对社会的正面影响。
      如果你做这件事情必须要让手下人做出牺牲,可能这件事根本不该做。
      要成为成功的技术领导,就不能对任何人的人性有丝毫的抑制。
      因为大多数人都希望帮助他人,而创造让人发挥更多能力的环间正是帮助他人的办法之一。
      有效帮助的开始,只能是双方都同意的对问题的清晰的定义。一定要多加检查,确认对方是否需要你的帮助。希望帮助其他人的人,通常都希望有所回报。
      保持真诚,无论你是否刻意。
      我们都觉得力量是“拥有”的,其实力量不是所有物,而是一种关系。
      通常,我们总会使用已知的最好的办法来解决问题,因此技术领导总是看到问题机械的一面。
      我们应该选择:是成为问题的一部分,还是成为办法的一部分。
      你或许必须在所有时候都做到完美,但肯定不必每次都有强力解决问题。
      力量如果不受约束,也没有指向与之匹配的更高目标,就必然蕴含危险。
      善于把我拥有的力量转换为更有用的形式。
      人们忙于做大事,没有时间来做那些组织本来应该做的事情。
      领导的职责通常不是解决单个的问题,而是创造一个环境,话多问题都可以在其中解决。
      组织不是要解决问题,而是要避免差问题,否则只能挣扎于问题之中,热衷于奖励低效的组织。
      组织的过程就是完成任务的过程。
      寻找真实情况和表面情况之间的差异。
      认识到对方的存在,然后找出一种能够正当容纳每种需求的组织形式。
      高层人物制定规则,也是在破坏旧的规则。
      逃避自己的弱点永远都不是一个好办法。
      经历一系列普通的、微小的改变,最终才能接触到宏大非凡的事物。
      领导面临的真正考验在于,没有危机的时候她在做什么。

      每天多赢得一点时间:不要做那些已经分配下去的任务,即使你必须让手下人犯错误;不要操心琐碎的细节;不要浪费时间来证明你全知全能;不要浪费时间来为浪费的时间争论。
      倾听其他人已经学到的知识。
      让其它人展示他们的聪明才智。
      弄清楚我希望改变什么,保留什么,是我自己的事情。
      寻求支持是强者的表现。
      做你真正想要做的事情。
      书不能取代与人一起工作的经验。

     
      增强系统在其所处环境中生存和发展的能力。若我们能做到这一点,就知道自己是有力量的。否则,其他一切力量的诱惑--控制、通知、特权、胁迫、报复、毫不退让、以不可或缺的地位作为要挟--都没有意义;他们是对力量的次等奖励(或者末等奖励);这样只能努力让人自以为有力量,或者看上去有力量;其实他们是缺乏力量的表现。系统力量的真正底线在于:你是否影响整个系统?你能否帮助系统更妥善有效地面对它所处的环境?
      如果你想做某件事情却一直找不到时间,那多半是你其实不想做。
      如果你想做某事,又苦于找不到时间:第一,对已经分配的任务,不要反复纠结;第二,对于实现过程中的细节,不要反复纠结;第三,不要让自己的生活被层出不穷的危机所支配。

      人不应当被作为机器对待,尤其因为技术工作强调思考和创新,所以技术工作者更不应当被视为机器,而应当被视为种子--蕴含内在力量,会不断发展成熟的种子。
      所谓领导力,就是创造一个环境,让所有的人都可以发挥出比单干时更大的价值,并不断成长。
      激励、组织、创新。

      奖励和惩罚可以对员工起到引导和归束的作用。 +
    -----------------------------------------------------------------------------------------------------
      Gerald M. Weinberg,美国杰出的专业作家和思想家,著有30多本书籍和数以百计的论文,其主题主要集中在两个方面:人与技术的结合;人的思维模式、思维习惯以及解决问题的方法。温伯格(Gerald M. Weinberg)首要的贡献集中于软件领域,他是从个体心理、组织行为和企业文化角度研究软件管理和软件工程的权威和代表人物。在超过40年的软件职业生涯中,温伯格从事过软件开发,软件项目管理、软件管理教学和咨询,他更是一位杰出的软件专业作家和思想家。 -- 百度百科

    展开全文
  • 关于C++ const 的全面总结

    万次阅读 多人点赞 2009-04-30 08:54:00
    } //如果在函数体内修改了i,编译器就会报错 4 可以很方便地进行参数的调整和修改 同宏定义一样,可以做到不变则已,一变都变 5 为函数重载提供了一个参考 class A { ...... void f(int i) {......} //一个函数 ...

        C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,本人根据各方面查到的资料进行总结如下,期望对朋友们有所帮助。

    Const 是C++中常用的类型修饰符,常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。

     

    一、Const作用

       如下表所示:

    No.

    作用

    说明

    参考代码

    1

    可以定义const常量

     

    const int Max = 100; 

    2

    便于进行类型检查

    const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误

    void f(const int i) { .........}
          //对传入的参数进行类型检查,不匹配进行提示

    3

    可以保护被修饰的东西

    防止意外的修改,增强程序的健壮性。

    void f(const int i) { i=10;//error! }
          //如果在函数体内修改了i,编译器就会报错

    4

    可以很方便地进行参数的调整和修改

    同宏定义一样,可以做到不变则已,一变都变

     

    5

    为函数重载提供了一个参考

     

    class A
    {
               ......
      void f(int i)       {......} //一个函数
      void f(int i) const {......} //上一个函数的重载
               ......
    };

    6

    可以节省空间,避免不必要的内存分配

    const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝

    #define PI 3.14159         //常量宏
    const doulbe  Pi=3.14159;  //此时并未将Pi放入ROM中
                  ......
    double i=Pi;   //此时为Pi分配内存,以后不再分配!
    double I=PI;  //编译期间进行宏替换,分配内存
    double j=Pi;  //没有内存分配
    double J=PI;  //再进行宏替换,又一次分配内存!

    7

     提高了效率

    编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高

     

     

     

     

    二、Const的使用

    1定义常量
    (1)const修饰变量,以下两种定义形式在本质上是一样的。它的含义是:const修饰的类型为TYPE的变量value是不可变的。

     TYPE const ValueName = value;
         const TYPE ValueName = value;


    (2)将const改为外部连接,作用于扩大至全局,编译时会分配内存,并且可以不进行初始化,仅仅作为声明,编译器认为在程序其他地方进行了定义.

         extend const int ValueName = value;

    2、指使用CONST
    (1)指针本身是常量不可变
         char* const pContent;

    (2)指针所指向的内容是常量不可变
         const char *pContent;

    (3)两者都不可变
          const char* const pContent;

    (4)还有其中区别方法,沿着*号划一条线:
    如果const位于*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;
    如果const位于*的右侧,const就是修饰指针本身,即指针本身是常量。

     

    3、函数中使用CONST

    (1)const修饰函数参数
    a.传递过来的参数在函数内不可以改变(无意义,因为Var本身就是形参)

    void function(const int Var);

    b.参数指针所指内容为常量不可变

    void function(const char* Var);

    c.参数指针本身为常量不可变(也无意义,因为char* Var也是形参)

    void function(char* const Var);

    d.参数为引用,为了增加效率同时防止修改。修饰引用参数时:

    void function(const Class& Var); //引用参数在函数内不可以改变

    void function(const TYPE& Var); //引用参数在函数内为常量不可变

    这样的一个const引用传递和最普通的函数按值传递的效果是一模一样的,他禁止对引用的对象的一切修改,唯一不同的是按值传递会先建立一个类对象的副本, 然后传递过去,而它直接传递地址,所以这种传递比按值传递更有效.另外只有引用的const传递可以传递一个临时对象,因为临时对象都是const属性, 且是不可见的,他短时间存在一个局部域中,所以不能使用指针,只有引用的const传递能够捕捉到这个家伙.


    (2)const 修饰函数返回值
        const修饰函数返回值其实用的并不是很多,它的含义和const修饰普通变量以及指针的含义基本相同。
        a.const int fun1() //这个其实无意义,因为参数返回本身就是赋值。
        b. const int * fun2() //调用时 const int *pValue = fun2();
                              //我们可以把fun2()看作成一个变量,即指针内容不可变。
        c.int* const fun3()   //调用时 int * const pValue = fun2();
                              //我们可以把fun2()看作成一个变量,即指针本身不可变。

    一般情况下,函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载。通常,不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。原因如下:如果返回值为某个对象为const(const A test = A 实例)或某个对象的引用为const(const A& test = A实例) ,则返回值具有const属性,则返回实例只能访问类A中的公有(保护)数据成员和const成员函数,并且不允许对其进行赋值操作,这在一般情况下很少用到。


    4、类相关CONST

    (1)const修饰成员变量
    const修饰类的成员函数,表示成员常量,不能被修改,同时它只能在初始化列表中赋值。
        class A
        {
            …
            const int nValue;        
    //成员常量不能被修改
            …
            A(int x): nValue(x) { } ;
    //只能在初始化列表中赋值
         }
     


    (2)const修饰成员函数
    const修饰类的成员函数,则该成员函数不能修改类中任何非const成员函数。一般写在函数的最后来修饰。
        class A
        {
            …

           void function()const; //常成员函数, 它不改变对象的成员变量.                        

    //也不能调用类中任何非const成员函数。
    }

    对于const类对象/指针/引用,只能调用类的const成员函数,因此,const修饰成员函数的最重要作用就是限制对于const对象的使用。

    a. const成员函数不被允许修改它所在对象的任何一个数据成员。

    b. const成员函数能够访问对象的const成员,而其他成员函数不可以。

     

    (3)const修饰类对象/对象指针/对象引用

    ·             const修饰类对象表示该对象为常量对象,其中的任何成员都不能被修改。对于对象指针和对象引用也是一样。

    ·             const修饰的对象,该对象的任何非const成员函数都不能被调用,因为任何非const成员函数会有修改成员变量的企图。
    例如:
    class AAA
    {
        void func1();
    void func2() const;
    }
    const AAA aObj;
    aObj.func1();
    ×
    aObj.func2(); 正确

    const AAA* aObj = new AAA();
    aObj-> func1();
    ×
    aObj-> func2(); 正确

     

    三、将Const类型转化为非Const类型的方法

     

    采用const_cast 进行转换。 
    用法:const_cast <type_id>  (expression)
    该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。

    ·             常量指针被转化成非常量指针,并且仍然指向原来的对象;

    ·             常量引用被转换成非常量引用,并且仍然指向原来的对象;

    ·             常量对象被转换成非常量对象。

     

    四、使用const的一些建议
     

    ·             要大胆的使用const,这将给你带来无尽的益处,但前提是你必须搞清楚原委;

    ·             要避免最一般的赋值操作错误,如将const变量赋值,具体可见思考题;

    ·             在参数中使用const应该使用引用或指针,而不是一般的对象实例,原因同上;

    ·             const在成员函数中的三种用法(参数、返回值、函数)要很好的使用;

    ·             不要轻易的将函数的返回值类型定为const;

    ·             除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;

    ·             任何不会修改数据成员的函数都应该声明为const 类型。

     

    五、补充重要说明

     

    ·             类内部的常量限制:使用这种类内部的初始化语法的时候,常量必须是被一个常量表达式

    初始化的整型或枚举类型,而且必须是static和const形式。

    ·             如何初始化类内部的常量:一种方法就是static 和 const 并用,在外部初始化,例如:

    class A { public: A() {} private: static const int i; file://注意必须是静态的! };

    const int A::i=3;另一个很常见的方法就是初始化列表: class A { public: A(int

    i=0):test(i) {} private: const int i; }; 还有一种方式就是在外部初始化,

    ·             如果在非const成员函数中,this指针只是一个类类型的;如果在const成员函数中,

    this指针是一个const类类型的;如果在volatile成员函数中,this指针就是一个

    volatile类类型的。

    ·             new返回的指针必须是const类型的。

    展开全文
  • 1 导言 每年国家统计局发布的...跨地域的集团型企业在运营管理上也有同样的问题。 随着计算机网络和通讯技术的进步、管理信息系统的不断成熟,为企业的运营管控模式提供了新的工具,为“全面集中管控型”企业业...
  • 为了实现性能并确保系统稳健性,就必须要进行系统监控测量...另外,全面了解传感器规范将确保在选择数字温度传感器器件时,可做到权衡得当。  当选择数字温度传感器(也称作串行输出温度传感器)时,应考虑的主要规范
  • :这里没有用声源定位,测向和定位是不太一样的,而消费级麦克风阵列做到测向就可以,定位则需要更多的成本投入。声源测向的主要作用就是侦测到与之对话人类的声音以便后续的波束形成。声源测向可以基于能量方法,也...
  • 为了实现最佳性能并确保系统稳健性,就必须要进行系统监控测量。...另外,全面了解传感器规范将确保在选择数字温度传感器器件时,可做到权衡得当。  当选择数字温度传感器(也称作串行输出温度传感器)时,应考虑
  • 前阵子做一个新闻发布系统,大量的用到ajax,中文乱码一直是个痛啊,通过大量的网上查询以下这篇文章能够很好的解决问题: 转载:http://blog.csdn.net/zhanngle/article/details/2063490 ajax乱码解决总结 第一,...
  • 全面认识Android OS

    万次阅读 多人点赞 2019-06-24 19:58:31
    但是要做到兼容的话,就必须对应用没有影 响 ——这就回到软件界的一句老话, 如果一个东西叫起来,走起路来都像鸭子的话,那它就是鸭子 。从这个角度看,自主实现只是为了搞成看起来和之前一样的话,这个意义并不...
  • 【硬核】Dubbo最全面试题 附答案

    万次阅读 多人点赞 2020-10-12 09:02:44
    如果你平时没有思考,没有往这方面想过答出来的东西就会没有条理性,会显得杂乱无章,不过你也不用慌张,不用想的很全面,答的很细致,没有必要,面试官要的是那些关键的重点。 你可以从底层向上开始说起。 首先...
  • Java基础问题整理

    万次阅读 多人点赞 2020-04-07 11:44:14
    备注:针对基本问题做一些基本的总结,不是详细解答! 1.HashMap和ConcurrentHashMap区别(必考) 2. ConcurrentHashMap的数据结构(必考) 3.高并发HashMap的环是如何产生的 4.HashMap1.7与HashMap1.8的区别,...
  • Google Exoplayer之全面认识

    万次阅读 2017-01-23 15:09:52
    支持定制和扩展,ExoPlayer是考虑到这一点而设计的,并允许许多部件与定制实现替换。 更新起来更方便 设备通用性更强 支持在Android 4.3(API级别18)和更高的Widevine通用加密。 需要注意的是,也有一些缺点,这...
  • 人工智能的若干伦理问题思考

    万次阅读 2018-02-07 00:00:00
    其次对人工智能伦理研究的常见问题进行了分析,并在最后对人工智能的伦理问题的发展进行了讨论。关键词:人工智能 伦理 人机环境交互 一、引言人工智能(Artificial Intelligence)一词起源于1956年的达特茅斯会议...
  • 首次的移动课堂,来到了美丽的天府之国- 四川... 魏杰老师:第一天:新常态下的宏观经济分析接下来将花2天时间来解说一下新常态经济下的宏观经济分析,目前中国经济存在的问题:第一个问题:中国经济新常态问题; -
  • 迁移学习全面概述

    千次阅读 2017-11-11 16:06:16
    深度 | 迁移学习全面概述:从基本概念到相关研究 2017-03-27 15:02无人驾驶/谷歌/操作系统 选自sebastianruder.com 作者:Sebastian Ruder 机器之心编译 参与:马亚雄、吴攀、李亚洲 将在一个...
  • 全面学习观和创新学习观

    千次阅读 2013-09-30 14:07:21
    全面的学习观 在我们的学校,对学生的奖励有评选“三好学生”,培养“德、智、体、美、劳全面发展的新一代接班人”被写进了国家的教育纲领。近年来,学生健全的心理素质受到重视,“心育”成为教育的新的补充目标。...
  • 质量成本管理指企业对保证和提高产品质量的成本,有组织,有系统地进行预测、决策、计划、反 映、控制、分析和考核等一...从而最大限度地调动员工的积 极性,努力挖掘降低成本的潜力,做到质量 成本的全面管理。 [1]
  • 全面解析plus token

    万次阅读 2019-09-03 23:11:35
    对冲搬砖简单讲解一下:刚才我们了解到人工搬砖第一问题面临各交易所价格信息的及时和全面获知并且去分析,第二问题是人工操作不如机器快速,这两个都被智能狗这套机器系统解决,但如按照常规搬砖,即使机器也遇到...
  • memcache集群考虑问题

    千次阅读 2013-06-27 23:48:46
    这几个问题会让您有更全面的认识。  memcached和MySQL的query cache相比,有什么优缺点?  把memcached引入应用中,还是需要不少工作量的。MySQL有个使用方便的query cache,可以自动地缓存SQL查询的...
  • 【视频编码格式】全面解析

    万次阅读 多人点赞 2017-11-04 12:46:34
    相信这个问题问出来,许多、、不同知识层次的人有不同的思考,但是答案却都有一个共同点就是:“混乱”。从我们在接触网络上面看电影以来,就会遇到从原先我们熟知的RMVB格式的视频到后来接触的MP4、3GP等格式的视频...
  • 计数问题(一)

    千次阅读 2015-07-29 17:52:11
    计数问题是我们在学习和生活中经常遇到的一类问题,如果能够学会和掌握计数问题思考方法,就可以使我们快捷、准确无误的解决一些实际问题,使我们考虑问题全面、更细致。 (一)阅读思考  在解决“计数问题”时...
  • 全面了解风控策略体系

    万次阅读 多人点赞 2020-06-28 14:09:48
    它约束着决策时做什么不做什么、先做什么后做什么、用什么方式做、做到什么程度等诸多方面的问题。 1.2.3 竞争性 策略经常带有竞争气息,竞争就有优劣势之分,策略可以根据己方条件制定: 优势策略:多维错维降维,...
  • 全面了解IDC数据中心

    万次阅读 2018-12-01 00:01:00
    机房的选材从防火、防静电等方面考虑。 1、墙:一般选材为彩钢板、铝塑板、刷漆等; 2、顶:一般都选择微孔铝合金天花,铝合金天花分两种,一是方板,一是条形板,根据客户喜欢,现在稍微上点规模的机房都选择无吊顶...
  • 程序猿更需要有全局观的高度思考问题

    千次阅读 热门讨论 2013-07-31 21:16:07
    程序猿更需要有全局观的高度思考问题。 把你放在什么位置上,你就能办成什么样的事儿。 这句话对程序猿来说,更加合适不过。如果你只是想在这个行业呆上三到五年,靠着自己强壮的身体,出几年青春饭之后就...
  • 第2章 Web全面性能测试模型性能测试、压力测试、负载测试、强度测试、稳定性测试、健壮性测试、……,这么多眼花缭乱的性能测试类型名称,估计很少有人能...为了解决这些问题,本章提出了“Web全面性能测试模型”。主
  • 全面了解小微信贷风控

    万次阅读 多人点赞 2020-03-28 12:47:01
    房抵贷嵌上企业的外壳 3.6.4 决策风险 依靠某一场景下的数据做风险决策,实际上只能反映企业的一部分经营状况 数据不一定真实 3.6.5 信用风险 目前企业征信信息还没有个人征信数据全面清晰,仍需进一步完善 某些中小...
  • 全面了解信贷业务流程

    万次阅读 多人点赞 2020-04-13 11:44:55
    用户生命周期 风险理解 风控建议 本着对读者负责的态度,笔者行文时尽可能做到以下几点:结构完整、内容真实、逻辑清晰、重点突出、删繁就简,用关键词、数据、配图和案例体现决策引擎的定义优势、应用方法、框架...
  • 遇到问题就记录下来,下次开发注意\color{red}{遇到问题就记录下来,下次开发注意}遇到问题就记录下来,下次开发注意 # 作为一个程序员要做到的几点: 1、需求研究透彻,想清楚,再动手写代码 2、看了需求要沟通!...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 97,868
精华内容 39,147
关键字:

如何做到全面的考虑问题