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

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

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

    posts - 56,  comments - 12,  trackbacks - 0

    PiecePicker 用于實現“片斷選擇算法”,片斷選擇算法在《Incentives Build Robustness in BitTorrent》一文中有介紹,我把相關內容列出來。

     

    BT的片斷選擇算法,綜合下面幾種策略。

     

    l         嚴格的優先級

        片斷選擇的第一個策略是:一旦請求了某個片斷的子片斷,那么該片斷剩下的子片斷優先被請求。這樣,可以盡可能快的獲得一個完整的片斷

     

    l         最少的優先

        每 個peer都優先選擇整個系統中最少的那些片斷去下載,而那些在系統中相對較多的片斷,放在后面下載,這樣,整個系統就趨向于一種更優的狀態。如果不用這 種算法,大家都去下載最多的那些片斷,那么這些片斷就會在系統中分布的越來越多,而那些在系統中相對較少的片斷仍然很少,最后,某些 peer 就不再擁有其它 peer 感興趣的片斷了,那么系統的參與者越來越少,整個系統的性能就下降。

     

    l         隨機的第一個片斷

        “最 少優先”的一個例外是在下載剛開始的時候。此時,下載者沒有任何片斷可供上傳,所以,需要盡快的獲取一個完整的片斷。而最少的片斷,通常只有某一個 peer擁有,所以,它可能比多個peers都擁有的那些片斷下載的要慢。因此,第一個片斷是隨機選擇的,直到第一個片斷下載完成,才切換到“最少優先” 的策略。

     

    l         最后階段模式

        有 時候,從一個速率很慢的peer那里請求一個片斷。在下載的中間階段,這不是什么問題,但是卻可能潛在的延遲下載的完成。為了防止這種情況,在最后階段, peer向它的所有的peers們都發送某片斷的子片斷的請求,一旦某些子片斷到了,那么就會向其它peer發送cancel 消息,取消對這些子片斷的請求,以避免帶寬的浪費。實際上,用這種方法并沒有浪費多少帶寬,而文件的結束部分也一直下載的非常快。

     

    下面是我在分析之前思考的兩個問題:

     

    問題1:如何實現“嚴格優先級”

    答案:記錄每個已經開始下載的片斷。優先選擇它們。

     

    問題2:如何實現“最少優先”算法?也就是你如何去統計某個片斷在系統中最少?

    答案:通過 have 消息(have消息請參看BT對等協議)來計算。在下載過程中,會不停的收到其它 peer 發來的 have 消息,每個have消息都表明對方擁有了某個片斷。那么,為每個片斷維護一個計數器,每收到一個have消息,相應的計數器加1。在選擇片斷的時候,計數 器最小的某個片斷被選中。

     

    在實際代碼中,可以看到,變量started和seedstarted 是用來實現“嚴格優先級”的,它們記錄了那些已經開始下載的片斷。而變量 numinterests用來實現“最少優先”算法。

     

    PiecePicker類的核心函數是 next() ,它綜合多種策略,來計算出下一個應該被選擇進行下載的片斷。

     

    PiecePicker 類的難點是三個變量 numinterests、interests、pos_in_interests的作用。因為沒有任何注釋,我思考了很久才明白它們的作用,特別是 pos_in_interests。所以,在分析代碼之前,我結合例子來講解這三個變量的作用。

     

    假設有三個片斷:

     

    numinterests:

    類型是list,每個片斷對應一項,記錄了每個片斷收到的 have 消息的個數。初始化的時候,numinterests = [0, 0, 0]。

     

    interests:

    類型是 list,它的每一項又是一個 list。例如在這個例子中,初始化的時候,interests = [ [0, 1, 2] ],顯然,它只有一項。

    interests 的作用是什么了?嗯,有點難以表達。大概是這樣的吧:所有未完成下載的片斷的索引號都保存在 interests,進行片斷選擇的時候,要用到 interests。我們看兩個例子:

    1、interests = [ [0, 1], [2]]

    2、interests = [ [1], [0, 2]]

    在第一個例子中,片斷0、1位于 interests 的第0項,片斷2位于 interests的第1項。

    在第二個例子中,片斷1位于位于 interests 的第0項,片斷0、2位于 interests的第1項。

    無論哪種情況,都表明0、1、2三個片斷都還沒有下載完成。

    那么,某個片斷到底應該處于 interests 中什么位置了?答案是根據該片斷收到的 have 消息個數,也就是 numinterests 的值。 例如,第一個例子中,說明片斷0、1收到的 have 個數都是0,所以處于 interests的第0項,而片斷2收到的 have 個數是1,所以處于第1項。而初始化的時候,interests =[ [0, 1, 2]],說明片斷0、1、2收到的 have個數都是0。

    奇怪,為什么要這樣設計了?答案就是“最少優先”的片斷選擇策略。我們看到,擁有越多 have 的片斷,在 interests 中,位置越靠后。在進行片斷選擇的時候,可能會從 interests中選一個片斷出來(為什么說可能了,一會可以看到,會優先采用其它策略,如果其它策略不能選一個出來,才會試圖從 interests 中選)。這樣,按照索引從小到大的順序,擁有 have 越少的片斷,越可能被選到。我們考慮這樣一個例子:

    interests = [[2, 3], [5, 0, 1], [], [], [4]]

    片斷2、3擁有0個 have,不能被選擇。(至少要有一個 have 才被考慮)。

    片斷0、1、5都有1個have,所以會優先從它們中選擇一個。

    片斷4擁有4個 have,所以最后被考慮。

     

    pos_in_interests:

    如上所述,擁有相同 have 個數的片斷,處于 interests 中的同一位置。例如上面這個例子,0、1、5都處于第1個位置。那么它們又根據什么原則進行先后排列了?答案是隨機排列。所以,既可能是0、1、5,也可 能是 1、5、0,或者其它。為了記錄某個片斷的確切位置,就需要用到 pos_in_interests了。它也是一個 list,每個片斷擁有一項,根據上面這個例子,應該是:

    pos_in_interests = [1, 2, 0, 1, 0, 0]

    看出什么來沒?呵呵

    它的意思是,

    片斷0是 [5, 0, 1] 的第1個

    片斷1是 [5, 0, 1] 的第2個

    片斷2是 [2, 3] 的第0個

    片斷3是 [2, 3] 的第1個

    片斷4是 [4] 的第0個

    片斷5是 [5, 0, 1] 的第0個

     

    就是這樣嘍,不知道我有沒有說清楚。

     

     

    # 封裝“片斷選擇算法”

    class PiecePicker:

        def __init__(self, numpieces, rarest_first_cutoff = 1):

            self.rarest_first_cutoff = rarest_first_cutoff

            self.numpieces = numpieces  # 片斷的個數

            self.interests = [range(numpieces)]

            self.pos_in_interests = range(numpieces)

            self.numinterests = [0] * numpieces

            self.started = []

            self.seedstarted = []

            self.numgot = 0 # 獲得了幾個片斷?

            self.scrambled = range(numpieces)

            shuffle(self.scrambled)

     

           收到一個 have 消息的處理

        def got_have(self, piece):

            if self.numinterests[piece] is None:

    return

                  numint = self.numinterests[piece]

            if numint == len(self.interests) - 1:

    self.interests.append([])

                  numinterests 對應的值要加 1

            self.numinterests[piece] += 1

                  調整 interests pos_in_interests

            self._shift_over(piece, self.interests[numint], self.interests[numint + 1])

     

           丟失一個 have 消息?????

        def lost_have(self, piece):

            if self.numinterests[piece] is None:

                return

            numint = self.numinterests[piece]

            self.numinterests[piece] -= 1

            self._shift_over(piece, self.interests[numint], self.interests[numint - 1])

     

           調整 interests pos_in_interests ,前面已經分析過。

        def _shift_over(self, piece, l1, l2):

            p = self.pos_in_interests[piece]

            l1[p] = l1[-1]

            self.pos_in_interests[l1[-1]] = p

            del l1[-1]

            newp = randrange(len(l2) + 1)

            if newp == len(l2):

                self.pos_in_interests[piece] = len(l2)

                l2.append(piece)

            else:

                old = l2[newp]

                self.pos_in_interests[old] = len(l2)

                l2.append(old)

                l2[newp] = piece

                self.pos_in_interests[piece] = newp

     

           為某個片斷發送過 requested 消息,用于“嚴格優先級”策略

        def requested(self, piece, seed = False):

            if piece not in self.started:

                         把片斷索引號添加到 started

                self.started.append(piece)

            if seed and piece not in self.seedstarted:

                self.seedstarted.append(piece)

     

        # 如果某個片斷已經得到,那么調用這個函數

        def complete(self, piece):

            assert self.numinterests[piece] is not None

            self.numgot += 1

     

            l = self.interests[self.numinterests[piece]]

            p = self.pos_in_interests[piece]

            l[p] = l[-1]

            self.pos_in_interests[l[-1]] = p

            del l[-1]

            self.numinterests[piece] = None

            try:

                self.started.remove(piece)

                self.seedstarted.remove(piece)

            except Error:

                pass

     

           計算下一個被選擇的片斷

        def next(self, havefunc, seed = False):

            bests = None

            bestnum = 2 ** 30

     

                  首先根據“嚴格優先級”策略,從已經開始下載的片斷中選擇。

            if seed:

                s = self.seedstarted

            else:

    s = self.started

     

    “嚴格優先級”策略是和“最少優先”策略結合起來使用的。也就是說,在滿足“嚴格優先”的片斷中,再去選擇一個滿足“最少優先”的片斷。注意,“最少優先”還有一個限制,就是如果一個片斷如果從來沒有收到過 have 消息(也就是計數是 0 ),也不能被選擇。這個判斷由下面的 havefunc(i) 完成。

                  for i in s:

                if havefunc(i):

                    if self.numinterests[i] < bestnum:

                        bests = [i]

                        bestnum = self.numinterests[i]

                    elif self.numinterests[i] == bestnum:

    bests.append(i)

     

    經過“嚴格優先級”和“最少優先”策略之后,可能返回多個候選片斷,從中隨機選擇一個,返回。

            if bests:

                         bests 隨機返回一個值

    return choice(bests)

     

     

    如果以上步驟,沒有選擇出一個片斷。那么隨機選擇一個。這大概就是“隨機的第一個片斷”的策略吧。因為 rarest_first_cutoff 默認是設置為 1 的。也就是說,在一個片斷都沒有獲得的情況下,才會選擇這種策略。如果 rarest_first_cutoff 設置為 10 ,那么這個策略就可以叫做“隨機的前 10 個片斷”,呵呵。

     

            if self.numgot < self.rarest_first_cutoff:

                for i in self.scrambled:

                    if havefunc(i):

                        return i

    return None

     

    如果不能采用“隨機的第一個片斷”測率,那么, interests 終于派上用場了。到這里,終于明白 interests 為什么要用 numinterests 對應的值來進行定位了。還是“最少優先”的思想,因為那些收到 have 消息少的片斷,在 interests 中位置比較靠前,所以會優先被選擇到。

            for i in xrange(1, min(bestnum, len(self.interests))):

                for j in self.interests[i]:

                    if havefunc(j):

    return j

     

                  如果還選不出來,只好返回 None 了。

            return None

     

        def am_I_complete(self):

            return self.numgot == self.numpieces

     

    誰來補充?

        def bump(self, piece):

            l = self.interests[self.numinterests[piece]]

            pos = self.pos_in_interests[piece]

            del l[pos]

            l.append(piece)

            for i in range(pos,len(l)):

    self.pos_in_interests[l[i]] = i
    posted on 2007-01-19 00:22 苦笑枯 閱讀(254) 評論(0)  編輯  收藏 所屬分類: P2P
    收藏來自互聯網,僅供學習。若有侵權,請與我聯系!

    <2007年1月>
    31123456
    78910111213
    14151617181920
    21222324252627
    28293031123
    45678910

    常用鏈接

    留言簿(2)

    隨筆分類(56)

    隨筆檔案(56)

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 国产精品深夜福利免费观看| 久久亚洲国产成人影院| 国产精品va无码免费麻豆| 三年片在线观看免费观看大全动漫| 鲁死你资源站亚洲av| 亚洲最大在线视频| 亚洲不卡av不卡一区二区| 亚洲国产精品一区二区三区久久| 在线观看视频免费完整版| 一区二区三区在线免费看| 两个人看的www视频免费完整版| 国产精品手机在线亚洲| 亚洲欧美日韩一区二区三区在线| 亚洲精品在线播放| 亚洲自偷自拍另类图片二区| 亚洲精品无码久久久久| 在线精品亚洲一区二区三区| 亚洲国产一级在线观看 | 久久亚洲国产中v天仙www| 亚洲国产成人五月综合网| 国产成人免费手机在线观看视频| 毛片大全免费观看| 成人免费无码视频在线网站| 成年黄网站色大免费全看| 亚欧免费视频一区二区三区| 在线观看免费中文视频| 99热在线精品免费播放6| 亚洲午夜免费视频| 久久成人a毛片免费观看网站| 国产一区二区三区免费| 国产免费一区二区视频| 免费无码一区二区三区蜜桃| 免费国产污网站在线观看| 精品国产麻豆免费人成网站| 叮咚影视在线观看免费完整版| 国产永久免费高清在线| 十八禁无码免费网站| 美女视频黄是免费的网址| 在线观看免费人成视频色9| 午夜成人免费视频| 免费观看亚洲人成网站|