<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理







    posted @ 2010-05-23 05:53 dennis 閱讀(863) | 評論 (0)編輯 收藏


    1、首先態度需要端正,做代碼的自我審查并不是否定自己,而是給自己將工作做得更好的一次機會。在審查過程中要盡量將自己作為一個旁觀者的心態去審查自己的代碼,盡管這比較困難。

    2、代碼審查離不開重構,在審查過程中發現任何壞味道都請使用重構去改善,發現缺乏測試的地方要及時補充測試,不要讓BUG遺漏。

    3、代碼的自我審查可能不是越早越好,隔一段時間之后回去看自己寫的東西,對一些設計上的選擇能有更客觀的評價,在審查的過程中可能需要重新去理解代碼,在此過程中可以檢查自己代碼的可讀性,并思考如何改善可讀性,切記代碼首先是給人讀的

    4、審查過程中需要記錄下一些犯下的錯誤,以及當時為什么會犯下這樣的錯誤,建立自己的bug數據庫,并時常review,在以后的工作中避免同樣的錯誤。

    5、代碼的自我審查應該是一個持續性的過程,而非特定時間的特定行動,時常審查自己的代碼,不僅能辨析自己的得失,還能夠進一步提高自己在未來工作中的設計能力和預見能力。

    6、代碼的自我審查跟團隊成員之間的相互review并不矛盾,在相互review之前做一個自我審查,有助于提高review的效率,包括可讀性的提高和一些一般錯誤的避免。

    7、代碼自我審查的一些常見注意點:
    (0)自認為絕不會出錯,并且從來沒有審查過的代碼。
    (1)注意else語句,if條件下的子語句通??赡苁莻€正常的流程,而else意味著異常的情況或者特殊的場景,你可能特別注意怎么處理正常的情況,卻忽略了else子句的實現細節,如該釋放的鎖沒釋放,該遞減的計數沒有遞減,該賦予特殊值卻沒有賦予等等。
    (2)注意空的方法,沒有方法體的方法,是不需要實現?還是忘了實現?
    (3)注意switch語句,有沒有忘了break?這種錯誤通過findbugs之類的靜態代碼檢查工具都能避免。
    (4)注意大塊的注釋,為什么這么多注釋?是代碼寫的很糟糕?還是遺留的注釋?遺留的注釋會誤導人,要及時刪除。
    (5)注意一些看起來“不合常理”的代碼,這樣的代碼很多都是基于所謂性能考慮而優化過的代碼,這樣的優化是否還需要?是否能去除這些“奇怪”的代碼也能實現正常的需求?
    (6)對客戶端的使用有假設的代碼,假設用戶只會這么用,假設用戶只會用到返回對象中的某些屬性,其他屬性一定不會用到?不要對客戶代碼做假設!這個客戶代碼包括外部用戶和調用這個模塊的內部代碼。
    (7)標注了FIXME、TODO之類task標簽的代碼,是否忘了修復BUG,實現功能?
    (8)任何超過15行以上的方法,這些方法是否能拆分成更細粒度的方法,并保持在同一個抽象層次上?
    (9)任何在代碼中出現的常量值,是否應該提取出來成為單獨的常量,常量的默認值設置是否合理?
    (10) 任何持有容器的代碼,提供了放入容器的方法,是否提供了從容器中移除對象的方法?確保沒有內存泄漏的隱患。
    (11)重構中提到的其他壞味道,別放過它們,但是也不要追求完美,OO不是圣杯,如果能簡單的實現一個算法,你不要引入3個對象和4個接口。
    (12)在review最后能列出一張清單,開列下該項目面臨的風險點,并提出解決辦法,然后按照這張清單去review關鍵代碼,著重檢查異常情況下的處理。風險點的review,我建議可以放在后面,在一般性錯誤解決之后進行,此時你對代碼也將再度變的熟悉。

    posted @ 2010-05-18 00:28 dennis 閱讀(6412) | 評論 (4)編輯 收藏

        笑死我了


    posted @ 2010-04-29 18:54 dennis 閱讀(1267) | 評論 (1)編輯 收藏

       
        Ruby Fiber指南(一)基礎
        Ruby Fiber指南(二)參數傳遞
        Ruby Fiber指南(三)過濾器
        Ruby Fiber指南(四)迭代器
        Ruby Actor指南(五)實現Actor

        寫這個指南的時候,計劃是第五章寫一個Fiber的應用例子,但是一時沒有想到比較好的例子,模仿《Programming in Lua》中的多任務下載的例子也不合適,因為Ruby中的異步HttpClient跟lua還是很不一樣的,體現不了Fiber的優點。因此,這第五節一直拖著沒寫。
        恰巧最近在小組中做了一次Erlang的分享,有人問到Erlang調度器的實現問題,這塊我沒注意過,那時候就根據我對coroutine實現actor的想法做了下解釋,后來思考了下那個解釋是錯誤的,Erlang的調度器是搶占式的,而通過coroutine實現的actor調度卻是非搶占的,兩者還是截然不同的。我在《Actor、Coroutine和Continuation的概念澄清》中提到coroutine可以實現actor風格,actor跟coroutine并沒有必然的聯系,這篇文章的目的就在于證明這一點,使用Ruby Fiber實現一個簡單的actor風格的庫,整個代碼不到100行。后面還會談到這個實現的缺點,以及我對Erlang調度器實現的理解。

        首先是monkey patch,給Thread和Fiber類加上兩個方法,分別用于獲取當前線程的調度器和Fiber對應的actor:
    class Thread
      
    #得到當前線程的調度器
      def __scheduler__
        @internal_scheduler
    ||=FiberActor::Scheduler.new
      end
    end

    class Fiber
      
    #得到當前Fiber的actor
      def __actor__
        @internal_actor
      end
    end

         這里實現的actor仍然是Thread內的,一個Thread只跑一個調度器,每個actor關聯一個Fiber。
         讓我們來想想調度器該怎么實現,調度器顧名思義就是協調actor的運行,每次挑選適當的actor并執行,可以想象調度器內部應該維護一個等待調度的actor隊列,Scheduler每次從隊列里取出一個actor并執行,執行完之后取下一個actor執行,不斷循環持續這個過程;在沒有actor可以調度的時候,調度器應該讓出執行權。因此調度器本身也是一個Fiber,它內部有個queue,用于維護等待調度的actor:
    module FiberActor
      
    class Scheduler
        
    def initialize
          @queue
    =[]
          @running
    =false
        end

        
    def run
          
    return if @running
          @running
    =true
          
    while true
            
    #取出隊列中的actor并執行
            while actor=@queue.shift
              begin
                actor.fiber.resume
              rescue 
    => ex
                puts 
    "actor resume error,#{ex}"
              end
            end
            
    #沒有任務,讓出執行權
            Fiber.yield
          end
        end

        
    def reschedule
          
    if @running
            
    #已經啟動,只是被掛起,那么再次執行
            @fiber.resume
          
    else
            
    #將當前actor加入隊列
            self << Actor.current
          end
        end

        
    def running?
          @running
        end

        
    def <<(actor)
          
    #將actor加入等待隊列
          @queue << actor unless @queue.last == actor
          
    #啟動調度器
          unless @running
             @queue 
    << Actor.current
             @fiber
    =Fiber.new { run }
             @fiber.resume
          end
        end
      end
    end

        run方法是核心的調度方法,注釋說明了主要的工作流程。因為調度器可能讓出執行權,因此提供了reschedule方法重新resume啟動調度器。<<方法用于將等待被調度的actor加入等待隊列,如果調度器沒有啟動,那么就啟動調度Fiber。

        有了調度器,Actor的實現也很簡單,Actor跟Fiber是一對一的關系,Actor內部維護一個mailbox,用來存儲接收到的消息。最重要的是receive原語的實現,我們這里很簡單,不搞模式匹配,只是接收消息。receive的工作流程大概是這樣,判斷mailbox中有沒有消息,有消息的話,取出消息并調用block處理,沒有消息的話就yield讓出執行權。

    module FiberActor  
      
    class Actor
        attr_accessor :fiber
        
    #定義類方法
        class << self
          
    def scheduler
            Thread.current.
    __scheduler__
          end

          
    def current
            Fiber.current.
    __actor__
          end

          
    #啟動一個actor
          def spawn(*args,&block)
            fiber
    =Fiber.new do
               block.call(args)
            end
            actor
    =new(fiber)
            fiber.instance_variable_set :@internal_actor,actor
            scheduler 
    << actor
            actor
          end

          
    def receive(&block)
            current.receive(
    &block)
          end
        end

        
    def initialize(fiber)
           @mailbox
    =[]
           @fiber
    =fiber
        end

        
    #給actor發送消息
        def << (msg)
          @mailbox 
    << msg
          
    #加入調度隊列
          Actor.scheduler << self
        end

        
    def receive(&block)
          
    #沒有消息的時候,讓出執行權
          Fiber.yield while @mailbox.empty?
          msg
    =@mailbox.shift
          block.call(msg)
        end

        
    def alive?
          @fiber.alive?
        end
      end

    end

        Actor.spawn用于啟動一個actor,內部其實是創建了一個fiber并包裝成actor給用戶,每個actor一被創建就加入調度器的等待隊列。<<方法用于向actor傳遞消息,傳遞消息后,該actor也將加入等待隊列,等待被調度。

        我們的簡化版actor庫已經寫完了,可以嘗試寫幾個例子,最簡單的hello world:
    include FiberActor

    Actor.spawn { puts 
    "hello world!"}
         輸出:
    hello world!

        沒有問題,那么試試傳遞消息:
    actor=Actor.spawn{
       Actor.receive{ 
    |msg|  puts "receive #{msg}"}
    }
    actor 
    << :test_message
        輸出:
    receive test_message
        
        也成了,那么試試兩個actor互相傳遞消息,乒乓一下下:
    pong=Actor.spawn do
          Actor.receive do 
    |ping|
            
    #收到ping,返回pong
            ping << :pong
          end
        end
    ping
    =Actor.spawn do
          
    #ping一下,將ping作為消息傳遞
          pong << Actor.current
          Actor.receive do 
    |msg|
            
    #接收到pong
            puts "ping #{msg}"
          end
        end
    #resume調度器
    Actor.scheduler.reschedule

         輸出:
    ping pong
        
         都沒有問題,這個超級簡單actor基本完成了。可以看到,利用coroutine來實現actor是完全可行的,事實上我這里描述的實現基本上是revactor這個庫的實現原理。revactor是一個ruby的actor庫,它的實現就是基于Fiber,并且支持消息的模式匹配和thread之間的actor調度,有興趣地可以去玩下。更進一步,其實采用輕量級協程來模擬actor風格早就不是新鮮主意,比如在cn-erlounge的第四次會議上就有兩個topic是關于這個,一個是51.com利用基于ucontext的實現的類erlang進程模型,一個是許世偉的CERL??梢韵胍?,他們的基本原理跟本文所描述不會有太大差別,那么面對的問題也是一樣。

         采用coroutine實現actor的主要缺點如下:
    1、因為是非搶占式,這就要求actor不能有阻塞操作,任何阻塞操作都需要異步化。IO可以使用異步IO,沒有os原生支持的就需要利用線程池,基本上是一個重復造輪子的過程。
    2、異常的隔離,某個actor的異常不能影響到調度器的運轉,簡單的try...catch是不夠的。
    3、多核的利用,調度器只能跑在一個線程上,無法充分利用多核優勢。
    4、效率因素,在actor數量劇增的情況下,簡單的FIFO的調度策略效率是個瓶頸,盡管coroutine的切換已經非常高效。

        當然,上面提到的這些問題并非無法解決,例如可以使用多線程多個調度器,類似erlang smp那樣來解決單個調度器的問題。但是如調度效率這樣的問題是很難解決的。相反,erlang的actor實現就不是通過coroutine,而是自己實現一套類似os的調度程序。
        首先明確一點,Erlang的process的調度是搶占式的,而非couroutine的協作式的。其次,Erlang早期版本是只有一個調度器,運行在一個線程上,隨著erts的發展,現在erlang的調度器已經支持smp,每個cpu關聯一個調度器,并且可以明確指定哪個調度器綁定到哪個cpu上。第三,Erlang的調度也是采用優先隊列+時間片輪詢的方式,每個調度器關聯一個ErtsRunQueueErtsRunQueue內部又分為三個ErtsRunPrioQueue隊列,分別對應high,max和normal,low的優先級,其中normal和low共用一個隊列;在Erlang中時間片是以reduction為單位,你可以將reduction理解成一次函數調用,每個被調度的process能執行的reduction次數是有限的。調度器每次都是從max隊列開始尋找等待調度的process并執行,當前調度的隊列如果為空或者執行的reductions超過限制,那么就降低優先級,調度下一個隊列。

       從上面的描述可以看出,Erlang優秀的地方不僅在于actor風格的輕量級process,另一個強悍的地方就是它的類os的調度器,再加上OTP庫的完美支持,這不是一般方案能山寨的。
        
        
      

    posted @ 2010-04-13 18:31 dennis 閱讀(5635) | 評論 (1)編輯 收藏

        在小組內做的一次分享,基本上是在鋒爺的一個PPT的基礎上做了一些擴充,對Erlang沒有了解過的朋友可以看看。

    posted @ 2010-04-12 10:45 dennis 閱讀(3473) | 評論 (0)編輯 收藏

        基本能說明整個設計以及運行時流程,最近搞文檔畫的。

    基本組件結構圖——典型的Reactor+handler模式



    一次IO讀請求的處理過程:





    posted @ 2010-03-26 14:19 dennis 閱讀(2275) | 評論 (1)編輯 收藏

    媽媽,我不想走
    ——紀念不幸逝去的孩子們!
    媽媽
    你為什么在哭泣
    今天不是我的生日
    為什么在我身旁點燃紅燭
    沒有歌聲
    也沒有小朋友
    只有你的淚水
    在不停地淌流
    媽媽,拽緊我的手
    我不想走
    媽媽
    你為什么在哭泣
    今天我又惹你生氣
    是我沒完成作業
    還是我偷偷在玩游戲
    你打我吧
    你罵我吧
    千萬不要把我拋棄
    媽媽,拽緊我的手
    我不想走
    媽媽
    你為什么哭泣
    是老天不公
    還是你的愛沒將我留住
    天堂沒有陽光
    也沒有鳥語花香
    我不去那邊當天使
    今生只想做你的心頭肉
    媽媽,拽緊我的手
    我不想走

    來自網易網友評論,新聞鏈接《福建南平男子在校門口殺害八名小學生


    posted @ 2010-03-24 09:48 dennis 閱讀(1033) | 評論 (0)編輯 收藏


    ??? Actor、CoroutineContinuation這三個概念由于并發的受關注而被經常提到,這里主要想談下這三者的區別和聯系,以便更好的區分問題領域和討論。首先,Actor和Coroutine在我看來是兩種并發模型,僅針對于并發這個領域,而Continuation則是程序設計領域的一個概念,相比于Actor和Coroutine是一個更基礎的概念。

    ??? 那么,什么是Continuation?這個要從表達式的求值說起。一個表達式的求值可以分為兩個階段:“What to evaluate?”和“What to do with the value”,“What to do with the value”就是計算的Continuation。以下面這段代碼為例:
    if?x<3?then
    ???
    return?x+1
    else
    ???
    return?x
    end

    ??? 考察其中的表達式x<3,這個表達式就是“what to evaluate?”,代表你將計算的東西,然后根據x<3的結果決定是執行x+1還是直接返回x,這個根據x<3的值來決定下一步的過程就是這個表達式的Continuation,也就是"what to do with the value"。怎么得到某個表達式的Continuation呢?在支持Continuation的語言里提供了call-with-current-continuation的函數,通常簡稱為call/cc,使用這個函數你就可以在任何代碼中得到Continuation。進一步,continuation有什么作用呢?它可以做的事情不少,如nonlocal exits、回溯、多任務的實現等等。例如在scheme中沒有break語句,就可以用call/cc實現一些此類高級的控制結構:

    (call/cc?(lambda?(break)
    ????????(
    for-each?(lambda?(x)?(if?(<?x?0)?(break?x)))
    ????????????????
    '(99?88?-77?66?55))
    ????????#t))


    ??? 上面這段代碼查找列表(99 88 -77 66 55)中的負數,當查找到的時候馬上從迭代中退出并返回該值,其中的break就是一個continuation。剛才還提到continuation可以實現回溯,那么就可以實現一個窮舉的機器出來用來搜索解空間,也就是類似Prolog中的回溯機制,在SICP這本書里就介紹了如何用call/cc實現一個簡單的邏輯語言系統。更著名的就是神奇的amb操作符,有興趣可以看看這里
    ????
    ???? 接下來我們來看看如何continuation實現多任務,在Continuation的維基百科里給了一段代碼來展示如何用scheme來實現coroutine,我稍微修改了下并添加了注釋:
    ;;continuation棧,保存了等待執行的continuation
    (define?call/cc?call-with-current-continuation)
    (define?*queue*?'())

    (define?(empty-queue?)
    ????????(null??*queue*))

    (define?(enqueue?x)
    ????????(set!?*queue*?(append?*queue*?(list?x))))

    (define?(dequeue)
    ????????(let?((x?(car?*queue*)))
    ??????????????(set!?*queue*?(cdr?*queue*))
    ?????????x))
    ;;啟動協程
    (define?(resume?proc)
    ???????(call/cc
    ?????????(lambda?(k)
    ???????????;;保存當前continuation,執行proc
    ???????????(enqueue?k)
    ???????????(proc))))
    ;;讓出執行權
    (define?(yield)
    ?????(call/cc
    ??????(lambda?(k)
    ?????????;;保存當前continuation,彈出上一次執行的cont并執行
    ????????(enqueue?k)
    ????????((dequeue)))))
    ;;停止當前協程或者當沒有一個協程時停止整個程序,最簡單的調度程序
    (define?(thread-exit)
    ?????(if?(empty-queue?)
    ?????????(exit)
    ?????????((dequeue))))
    (注:scheme以分號開頭作為注釋)

    ???? 這其實就是一個coroutine的簡單實現,context的保存、任務的調度、resume/yield原語……樣樣俱全。使用起來類似這樣,下面這段程序輪流打印字符串:
    (define?(display-str?str)
    ????????(lambda()
    ?????????(let?loop()
    ??????????????(display?str)
    ??????????????(newline)
    ??????????????(yield)
    ??????????????(loop))))

    ;;;創建兩個協程并啟動調度器
    (resume?(display-str?"This?is?AAA"))
    (resume?(display-str?"Hello?from?BBB"))
    (thread-exit)

    ???? 任務非常簡單,打印下傳入的字符串并換行,然后讓出執行權給另一個任務執行,因此輸出:
    This?is?AAA
    Hello?from?BBB
    This?is?AAA
    Hello?from?BBB
    This?is?AAA
    Hello?from?BBB
    This?is?AAA
    Hello?from?BBB
    ……

    ??? 談了這么多continuation的應用,事實上我想說明的是continuation可以用來實現協程,Ruby 1.9中call/cc和Fiber的實現(在cont.c)大體是一樣的同樣說明了這一點。

    ???? 接下來我們討論下Actor和Coroutine的關系,上面提到Actor是一種并發模型,我更愿意稱之為一種編程風格,Actor跟message passing、Duck Typing是一脈相承的。Actor風格是可以這么描述:將物理世界抽象成一個一個的Actor,Actor之間通過發送消息相互通信,Actor不關心消息是否能被接收或者能否投遞到,它只是簡單地投遞消息給其他actor,然后等待應答。Actor相比于Coroutine是一種更高層次的抽象,它提供的receive和pattern match的原語更接近于現實世界,而使用coroutine編程你還需要手工介入任務調度,這在Actor中是由一個調度器負責的。

    ??? 同樣,Actor可以用coroutine實現,例如Ruby有個revactor項目,就是利用1.9引入的Fiber實現actor風格的編程,它的實現非常簡單,有興趣地可以看看,其實跟continuation實現coroutine類似。但是Actor并不是一定要用coroutine才能實現,Actor是一種編程風格,你在Java、C#、C++中同樣可以模擬這樣的方式去做并發編程,.net社區的老趙實現過一個簡單的ActorScala的Actor實現是基于外部庫,利用scala強大的元編程能力使得庫的使用像內置于語言。

    ??? 總結下我想表達的:Continuation是程序設計領域的基礎概念,它可以用于實現coroutine式的多任務,Actor是一種比之coroutine更為抽象的編程風格,Actor可以基于Coroutine實現但并非必須,Actor和Coroutine都是現在比較受關注的并發模型。



    posted @ 2010-03-23 11:49 dennis 閱讀(7648) | 評論 (0)編輯 收藏

    Google正式退出中國,跟朋友的聊天記錄:

    : 真到那天,是中國IT業的悲哀
    ?某人: 不僅僅是it業
    ??這是一個標志
    ??鐵幕再次拉開
    ??中國已經不在乎外部形象了
    ??也不在乎自己的工程師是否能和世界交流了
    ?只求政權穩定

    ??? 能移民的趕緊吧,不能移民的繼續被綁架,被代表,被河蟹,喝三鹿,打疫苗,得永生。

    posted @ 2010-03-23 09:25 dennis 閱讀(1037) | 評論 (2)編輯 收藏

    有興趣地瞧瞧吧,寫的匆忙。

    posted @ 2010-03-20 17:33 dennis 閱讀(3784) | 評論 (4)編輯 收藏

    僅列出標題
    共56頁: First 上一頁 9 10 11 12 13 14 15 16 17 下一頁 Last 
    主站蜘蛛池模板: 中文字幕一精品亚洲无线一区| 国产午夜精品久久久久免费视 | 免费国产午夜高清在线视频| 亚洲色大成网站www永久| 日韩a级无码免费视频| 亚洲一区二区三区偷拍女厕| a级毛片免费观看网站| 亚洲综合伊人久久综合| **aaaaa毛片免费同男同女| 亚洲丝袜美腿视频| 中文字幕免费视频| 久久乐国产综合亚洲精品| 成在线人永久免费视频播放| 亚洲6080yy久久无码产自国产 | 国产一区二区三区免费看 | 最近最新的免费中文字幕| 学生妹亚洲一区二区| 国产福利电影一区二区三区,亚洲国模精品一区 | 青青操免费在线观看| 国产AV无码专区亚洲AV男同| 国产成人免费ā片在线观看老同学 | 国内精品久久久久影院免费| 亚洲国产欧美国产综合一区 | 国产自国产自愉自愉免费24区| 亚洲国产系列一区二区三区| 国产亚洲婷婷香蕉久久精品| 亚洲黄色免费网址| 一级毛片在线播放免费| 亚洲人成网www| 亚洲精品美女久久久久99小说| 精品四虎免费观看国产高清午夜| 亚洲欧美日本韩国| 亚洲中文字幕无码中文字在线 | 亚洲精品国产福利一二区| 妻子5免费完整高清电视| 亚洲AV色无码乱码在线观看| 亚洲日韩在线视频| 免费一级毛片清高播放| 免费毛片a线观看| 国产成人无码精品久久久免费 | 免费大黄网站在线观看|