Fibonacci數(shù)列高效解法大全及時間復雜度分析 連載【9】

在數(shù)學上萄金,斐波那契數(shù)列是以遞歸的方法來定義

……續(xù)上回Fibonacci數(shù)列高效解法大全及時間復雜度分析 連載【8】

在家用電腦、手機都是一堆核心,數(shù)框框的今日

自然會想到的一項提速手段是——并行運算

就以 Fibonacci數(shù)列高效解法大全及時間復雜度分析 連載【7】中第14節(jié)的“生成數(shù)列的GMP內置fib2函數(shù)解法”來說

生成從0至n的斐波那契數(shù)列是一個數(shù)算完放入結果列表争舞,再算下一個數(shù)

這完全可以用我們的CPU多核同時算幾個數(shù),四核的話同時算四個數(shù)多好多快,完美

這就是分布在多核的多進程并行算法

四核下會是單核的4倍速嗎?也就是加速比能到達4嗎尼桶?

以四核為例,當實現(xiàn)加速比為4锯仪,那么并行算法效率就為100%

呃泵督,那是理想狀態(tài),實際遠遠到不了

到不了的原因在于變成多核多進程庶喜,一個大任務要在主進程分解成幾個子任務(子進程)分配到各核運算小腊,子任務算完后再匯總回主進程,這就有了附加開銷久窟。包括任務分解秩冈、任務調度、傳參斥扛、子進程上下文切換漩仙、進程間傳遞數(shù)據(jù)、進程間同步鎖犹赖、結果合并等,這些開銷很大卷仑。讓效率下降不少

就生成斐波那契數(shù)列而言峻村,實現(xiàn)其并行算法,中間開銷最大的應該是進程間傳遞數(shù)據(jù)锡凝,子進程要返回主進程超大規(guī)模的數(shù)據(jù)

那么對于單機這情況粘昨,都知道通常是共享內存方式最快

可以套用時髦的概念“內存計算

那么下面我來實現(xiàn)一下,共享內存并行算法


17.? 共享內存并行解法

import time

import multiprocessing as mp

import ctypes

import array

import gmpy2

def fib2_processes(shared_array_for_fib_seq_results: 'array ctypes.c_c_ulonglong', element_length_record: 'array ctypes.c_ulonglong', write_protection_pointer: 'ctypes.c_longlong', unread_quantity: 'ctypes.c_ulonglong', shared_array_overflow: 'ctypes.c_bool', mutexlock: 'Lock', n_iterable: 'iterable') -> None:

? ? start_time = time.process_time_ns()

? ? Fib_seq_array_size = len(shared_array_for_fib_seq_results)

? ? sizeof_c_ulonglong = ctypes.sizeof(ctypes.c_ulonglong)

? ? write_pointer = 0

? ? for n in n_iterable:

? ? ? ? for element in gmpy2.fib2(n):

? ? ? ? ? ? element_bytes = gmpy2.to_binary(element)[2:]

? ? ? ? ? ? element_byte_length = len(element_bytes)

? ? ? ? ? ? element_length = (element_byte_length >> 3) + (0 if element_byte_length & 0b111 == 0 else 1)

? ? ? ? ? ? next_write_pointer = write_pointer + element_length

? ? ? ? ? ? while shared_array_overflow.value and (next_write_pointer > write_protection_pointer.value):

? ? ? ? ? ? ? ? pass? #在溢出狀態(tài)未消除情況下窜锯,如果要寫入的范圍高于寫保護张肾,就空轉等待。

? ? ? ? ? ? if next_write_pointer > Fib_seq_array_size:

? ? ? ? ? ? ? ? shared_array_overflow.value = True

? ? ? ? ? ? ? ? write_pointer = 0

? ? ? ? ? ? ? ? next_write_pointer = element_length

? ? ? ? ? ? element_length_record[n] = element_length

? ? ? ? ? ? with mutexlock:

? ? ? ? ? ? ? ? shared_array_for_fib_seq_results[write_pointer: next_write_pointer] = array.array('Q', element_bytes + (b'\x00' * (element_length * sizeof_c_ulonglong - element_byte_length)))

? ? ? ? ? ? ? ? unread_quantity.value += 1

? ? ? ? ? ? write_pointer = next_write_pointer

? ? ? ? ? ? n -= 1

? ? end_time = time.process_time_ns()

? ? print ('計算和序列化用時 %.1f seconds.' % ((end_time - start_time)/10**9))

? ? return None

def Fibonacci_sequence_21 (n: int) -> list:? #參數(shù)n是表示求n項Fibonacci數(shù)列

? ? '多進程共享內存的返回列表的GMP內置fib函數(shù)解法'

? ? assert isinstance(n, int), 'n is an error of non-integer type.'

? ? if n>=0:

? ? ? ? start_time = time.process_time_ns()

? ? ? ? Number_of_processes = max(mp.cpu_count() - 1, 1)

? ? ? ? size_of_shared_variables_for_fib_processes = 1 * (1024 ** 2) // ctypes.sizeof(ctypes.c_ulonglong) // Number_of_processes? #就是占用的內存數(shù)量锚扎,1的單位MB吞瞪。注意太大的n也要隨之加大這個尺寸

? ? ? ? list_of_shared_array_for_fib_seq_results = []

? ? ? ? list_of_element_length_record = []

? ? ? ? list_of_write_protection_pointer = []

? ? ? ? list_of_unread_quantity = []

? ? ? ? list_of_shared_array_overflow = []

? ? ? ? list_of_mutexlock = []

? ? ? ? element_length_record = mp.RawArray(ctypes.c_ulonglong, n + 1)

? ? ? ? for i in range(Number_of_processes):

? ? ? ? ? ? list_of_shared_array_for_fib_seq_results.append(mp.RawArray(ctypes.c_ulonglong, size_of_shared_variables_for_fib_processes))

? ? ? ? ? ? list_of_element_length_record.append(element_length_record)

? ? ? ? ? ? list_of_write_protection_pointer.append(mp.RawValue(ctypes.c_longlong, -1))

? ? ? ? ? ? list_of_unread_quantity.append(mp.RawValue(ctypes.c_ulonglong, 0))

? ? ? ? ? ? list_of_shared_array_overflow.append(mp.RawValue(ctypes.c_bool, False))

? ? ? ? ? ? list_of_mutexlock.append(mp.Lock())

? ? ? ? list_of_n_iterable_for_fib2_processes = [range(n - i * 2, 0, -(Number_of_processes * 2)) for i in range(Number_of_processes)]

? ? ? ? fib2_process_list = [None] * Number_of_processes

? ? ? ? for i in range(Number_of_processes):

? ? ? ? ? ? fib2_process_list[i] = mp.Process(target = fib2_processes, args = (list_of_shared_array_for_fib_seq_results[i], list_of_element_length_record[i], list_of_write_protection_pointer[i], list_of_unread_quantity[i], list_of_shared_array_overflow[i], list_of_mutexlock[i], list_of_n_iterable_for_fib2_processes[i]))

? ? ? ? ? ? fib2_process_list[i].start()

? ? ? ? fib_list = [None] * (n + 1)

? ? ? ? n_list_for_fib2_processes = []

? ? ? ? for n_iterable in list_of_n_iterable_for_fib2_processes:

? ? ? ? ? ? n_list_for_fib2_processes.append(list(n_iterable))

? ? ? ? mv_list_of_results = []

? ? ? ? for i in range(Number_of_processes):

? ? ? ? ? ? mv_list_of_results.append(memoryview(list_of_shared_array_for_fib_seq_results[i]))

? ? ? ? list_of_pointers_to_n_list = [0] * Number_of_processes

? ? ? ? list_of_number_of_reciprocating = [0] * Number_of_processes

? ? ? ? list_of_read_pointer =? [0] * Number_of_processes

? ? ? ? while True:

? ? ? ? ? ? if mp.active_children() == []:? #檢測 當全部子進程都不是活的以后,進行下一個檢測準備結束循環(huán)

? ? ? ? ? ? ? ? for unread_quantity in list_of_unread_quantity:

? ? ? ? ? ? ? ? ? ? if unread_quantity.value != 0: break

? ? ? ? ? ? ? ? else:? ? #檢測當所有進程結果的未讀數(shù)都等于零就結束循環(huán)

? ? ? ? ? ? ? ? ? ? break

? ? ? ? ? ? for i in range(Number_of_processes):

? ? ? ? ? ? ? ? if list_of_unread_quantity[i].value != 0:

? ? ? ? ? ? ? ? ? ? n_for_fib2_processes = n_list_for_fib2_processes[i][list_of_pointers_to_n_list[i]] - list_of_number_of_reciprocating[i]

? ? ? ? ? ? ? ? ? ? next_read_pointer = list_of_read_pointer[i] + list_of_element_length_record[i][n_for_fib2_processes]

? ? ? ? ? ? ? ? ? ? if next_read_pointer > size_of_shared_variables_for_fib_processes:

? ? ? ? ? ? ? ? ? ? ? ? list_of_read_pointer[i] = 0

? ? ? ? ? ? ? ? ? ? ? ? next_read_pointer = list_of_element_length_record[i][n_for_fib2_processes]

? ? ? ? ? ? ? ? ? ? ? ? list_of_shared_array_overflow[i].value = False

? ? ? ? ? ? ? ? ? ? fib_list[n_for_fib2_processes] = int.from_bytes(mv_list_of_results[i][list_of_read_pointer[i]: next_read_pointer], 'little')

? ? ? ? ? ? ? ? ? ? with list_of_mutexlock[i]:

? ? ? ? ? ? ? ? ? ? ? ? list_of_unread_quantity[i].value -= 1

? ? ? ? ? ? ? ? ? ? ? ? list_of_read_pointer[i] = next_read_pointer

? ? ? ? ? ? ? ? ? ? ? ? list_of_write_protection_pointer[i].value = next_read_pointer

? ? ? ? ? ? ? ? ? ? list_of_pointers_to_n_list[i] += list_of_number_of_reciprocating[i]

? ? ? ? ? ? ? ? ? ? list_of_number_of_reciprocating[i] ^= 1

? ? ? ? if n & 1 == 0:

? ? ? ? ? ? fib_list[0] = 0

? ? ? ? end_time = time.process_time_ns()

? ? ? ? print ('主進程用時 %.1f seconds.' % ((end_time - start_time)/10**9))

? ? ? ? return fib_list

? ? else:

? ? ? ? return None

if __name__ == '__main__':

? ? ? ? start_time = time.perf_counter()

? ? ? ? Fibonacci_sequence_21(1000000)

? ? ? ? end_time = time.perf_counter()

? ? ? ? print ('最終用時 %.1f seconds.' % (end_time - start_time))

在我的四核16GB物理內存電腦上算100萬斐波那契數(shù)列(數(shù)據(jù)總占用內存40GB驾孔,所以包括虛擬內存)用時為:

1134秒

在之前14節(jié)單進程解法算100萬斐波那契數(shù)列用時為:

1857秒

縮短用時38.9%

然而這是4核并行芍秆,并行效率為40.9%((1857/1134)/4=0.409)。效率一般的并行算法

各位大佬翠勉,以14節(jié)那個單進程解法為基礎妖啥,來嘗試寫出你們的高效并行解法

我設個獎勵,按上面條件寫出并行效率>50%对碌,獎64¥

并行效率>60%荆虱,獎128¥

并行效率>70%,獎256¥

并行效率>80%,獎512¥

并行效率>90%怀读,獎1024¥

封頂了诉位,沒有了

請在下方留言吧,并給我私信

結尾愿吹,嘿不从,歡迎點贊和贊賞支持

未完待續(xù)……

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市犁跪,隨后出現(xiàn)的幾起案子椿息,更是在濱河造成了極大的恐慌,老刑警劉巖坷衍,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寝优,死亡現(xiàn)場離奇詭異,居然都是意外死亡枫耳,警方通過查閱死者的電腦和手機乏矾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來迁杨,“玉大人钻心,你說我怎么就攤上這事∏π” “怎么了捷沸?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長狐史。 經(jīng)常有香客問我痒给,道長,這世上最難降的妖魔是什么骏全? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任苍柏,我火速辦了婚禮,結果婚禮上姜贡,老公的妹妹穿的比我還像新娘试吁。我一直安慰自己,他們只是感情好楼咳,可當我...
    茶點故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布潘悼。 她就那樣靜靜地躺著,像睡著了一般爬橡。 火紅的嫁衣襯著肌膚如雪治唤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天糙申,我揣著相機與錄音宾添,去河邊找鬼。 笑死,一個胖子當著我的面吹牛缕陕,可吹牛的內容都是我干的粱锐。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼扛邑,長吁一口氣:“原來是場噩夢啊……” “哼怜浅!你這毒婦竟也來了?” 一聲冷哼從身側響起蔬崩,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤恶座,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后沥阳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體跨琳,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年桐罕,在試婚紗的時候發(fā)現(xiàn)自己被綠了脉让。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡功炮,死狀恐怖溅潜,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情薪伏,我是刑警寧澤伟恶,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站毅该,受9級特大地震影響,放射性物質發(fā)生泄漏潦牛。R本人自食惡果不足惜眶掌,卻給世界環(huán)境...
    茶點故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望巴碗。 院中可真熱鬧朴爬,春花似錦、人聲如沸橡淆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽逸爵。三九已至具滴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間师倔,已是汗流浹背构韵。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工镊逝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人逐工。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓睹晒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親显拳。 傳聞我的和親對象是個殘疾皇子棚愤,可洞房花燭夜當晚...
    茶點故事閱讀 44,647評論 2 354

推薦閱讀更多精彩內容

  • 他覺得有點輕松。那種努力過后的愉快杂数。但是在一秒過后宛畦,這種感覺就變得微弱。他想什么耍休,一切都變得難以去理解刃永。他昨天看到...
    鹿鹿無畏閱讀 727評論 0 49
  • 南宮雪冷哼一聲,酸溜溜的道:“這便是那位幫他付賬的姑娘了羊精。我早說過她不是什么好人家的女子斯够,你偏是不信⌒酰”李亦杰道:...
    _____以歿炎涼閱讀 287評論 0 0
  • | 零基礎學水彩 | 繁花盛開读规,萬紫千紅,惹人憐愛~燃少。 7月份畫了這幅束亏,當時沒打算寫文章,所以沒拍步驟圖~阵具。那就拿...
    amei楊_閱讀 540評論 0 0
  • 今天陪軒寶上親子課碍遍,寶寶很開心的玩,但是我發(fā)現(xiàn)了寶寶玩球的時候我說他沒有按照老師的要求玩阳液,我教他他沒學會怕敬,我覺得對...
    軒寶麻麻閱讀 150評論 0 0