Python高級語法1:GIL鎖&淺拷貝&深拷貝

一、GIL鎖

  • 1.1、GIL面試題:描述Python GIL的概念, 以及它對python多線程的影響?編寫一個多線程抓取網(wǎng)頁的程序,并闡明多線程抓取程序是否可比單線程性能有提升,并解釋原因。

    • Guido的聲明: he language doesn't require the GIL -- it's only the CPython virtual machine that has historically been unable to shed it.
  • 1.2、參考答案:

    • (1)、Python語言和GIL沒有半毛錢關(guān)系。僅僅是由于歷史原因在Cpython虛擬機(jī)(解釋器),難以移除GIL。
    • (2)、GIL:全局解釋器鎖。每個線程在執(zhí)行的過程都需要先獲取GIL,保證同一時刻只有一個線程可以執(zhí)行代碼。
    • (3)、線程釋放GIL鎖的情況: 在IO操作等可能會引起阻塞的system call之前,可以暫時釋放GIL,但在執(zhí)行完畢后,必須重新獲取GIL Python 3.x使用計時器(執(zhí)行時間達(dá)到閾值后,當(dāng)前線程釋放GIL)或Python 2.x,tickets計數(shù)達(dá)到100
    • (4)、Python使用多進(jìn)程是可以利用多核的CPU資源的。
    • (5)、多線程爬取比單線程性能有提升,因?yàn)橛龅絀O阻塞會自動釋放GIL鎖

二、淺拷貝

  • 2.1、淺拷貝是對于一個對象的頂層拷貝,簡單的理解是:拷貝了引用,并沒有拷貝內(nèi)容

  • 2.2、 看一個最簡單的淺拷貝

    最簡單的淺拷貝

    以上:a 與 b 的內(nèi)存地址相同,說明了當(dāng)給一個變量賦值的時候,其實(shí)就是將數(shù)據(jù)的引用賦值了一份給另外一個變量,這其實(shí)就是最簡單的淺拷貝,不僅列表是這樣,只要是 類似于 xx1 = xx2 的這種基本都是 淺拷貝,如下:

    >>> c = {"age":23}
    >>> d = c
    >>> id(c)
    4527333240
    >>> id(d)
    4527333240
    >>> c["name"] = "王小二"
    >>> c
    {'age': 23, 'name': '王小二'}
    >>> d
    {'age': 23, 'name': '王小二'}
    

    因?yàn)槎际菧\拷貝,所以只要通過一個引用進(jìn)行了修改,那么另外一個變量就看到的數(shù) 據(jù)也就變化了

  • 2.3、import copy 模塊中 copy.copy() 的使用

    >>> a = [11,22]
    >>> b = [33,44]
    >>> c = [a,b]
    >>> id(a)
    4528760776
    >>> id(b)
    4528427464
    >>> id(c)
    4528012488
    >>> import copy
    >>> d = copy.copy(c)
    >>> id(d)
    4528788488
    >>> id(d[0])
    4528760776
    >>> id(d[1])
    4528427464
    >>> a.append(55)
    >>> c
    [[11, 22, 55], [33, 44]]
    >>> d
    [[11, 22, 55], [33, 44]]
    
    淺拷貝只會復(fù)制最頂層的那個列表

    淺拷貝 只會復(fù)制最頂層的那個列表

三、深拷貝

  • 3.1、深拷貝是對于一個對象所有層次的拷貝(遞歸)

    >>> a = [11,22]
    >>> b = copy.deepcopy(a)
    >>> a
    [11, 22]
    >>> b
    [11, 22]
    >>> id(a)
    4528761928
    >>> id(b)
    4528933000
    

    以上結(jié)果通過deepcopy()確實(shí)將列表 a 中所有的數(shù)據(jù)的引用 copy 了,而不是只拷貝了 a 指向的列表的引用,看如下,a的數(shù)據(jù)發(fā)生變化的時候,b并不會發(fā)生變化

    >>> a.append(55)
    >>> a
    [11, 22, 55]
    >>> b
    [11, 22]
    
  • 3.2、進(jìn)一步理解 深拷貝

    進(jìn)一步理解 深拷貝

    深拷貝: 我個人理解其實(shí)是:深拷貝后與原來的對象沒有任何關(guān)系了,不管原來的對象如何變化,都不再會影響到深拷貝后的對象

四、拷貝的其他方式

  • 4.1、分片表達(dá)式 可以賦值一個序列

    >>> a = [11,22]
    >>> b = [33,44]
    >>> c = [a,b]
    >>> d = c[:]
    >>> id(c)
    4528760776
    >>> id(d)
    4528932936
    >>> id(c[0])
    4528933000
    >>> id(d[0])
    4528933000
    >>> a
    [11, 22]
    >>> a.append(55)
    >>> c
    [[11, 22, 55], [33, 44]]
    >>> d
    [[11, 22, 55], [33, 44]]
    
    d=c[:]與d=copy.copy(c)一樣 屬于淺拷貝

    d=c[:]d=copy.copy(c) 一樣 屬于 淺拷貝

  • 4.2、字典的copy方法可以拷貝一個字典


    字典的copy方法可以拷貝一個字典

五、注意點(diǎn)

  • 5.1、淺拷貝對不可變類型和可變類型的copy不同

    • copy.copy 對于 可變類型,會進(jìn)行淺拷貝

      >>> a = [11,22]
      >>> b = copy.copy(a)
      >>> id(a)
      4528932552
      >>> id(b)
      4528932680
      >>> a.append(33)
      >>> a
      [11, 22, 33]
      >>> b
      [11, 22]
      

      解釋一下大家的對于a變化,而b不變化的問題,因?yàn)閎拷貝的是a里面 11,22引用的指向,當(dāng)a添加 33的時候,而 11,22引用的指向并沒有發(fā)生變化,所以并不會發(fā)生變化

    • copy.copy 對于 不可變類型,不會拷貝,僅僅是指向

      >>> a = (11,22,33)
      >>> b = copy.copy(a)
      >>> id(a)
      4528768632
      >>> id(b)
      4528768632
      
    • 如果c是元組,那么copy時會,僅僅是元組的引用copy,而 deepcopy依然是深copy,即遞歸copy所有

      >>> a = [11,22]
      >>> b = [33,44]
      >>> c = (a,b)
      >>> d = copy.copy(c)
      >>> id(c)
      4528885256
      >>> id(d)
      4528885256
      >>> a.append(55)
      >>> c
      ([11, 22, 55], [33, 44])
      >>> d
      ([11, 22, 55], [33, 44])
      >>> e = copy.deepcopy(c)
      >>> id(c)
      4528885256
      >>> id(e)
      4528885448
      >>> a.append(66)
      >>> c
      ([11, 22, 55, 66], [33, 44])
      >>> e
      ([11, 22, 55], [33, 44])
      >>> 
      
  • 5.2、copy.copy和copy.deepcopy的區(qū)別

    • copy.copy

      >>> a = [11,22]
      >>> b = (a,)
      >>> c = [b,]
      >>> 
      >>> d = copy.copy(c)
      >>> 
      >>> c
      [([11, 22],)]
      >>> d
      [([11, 22],)]
      >>> a.append(33)
      >>> c
      [([11, 22, 33],)]
      >>> d
      [([11, 22, 33],)]
      >>> id(c)
      4528932936
      >>> id(d)
      4528012488
      >>> id(c[0])
      4528434200
      >>> id(d[0])
      4528434200
      
      copy.copy

      d = c # 讓d這個變量指向c指向的空間,d = copy.copy(c) # 復(fù)制所有c指向的數(shù)據(jù)到一個新的空間,但是不會遞歸copy

    • copy.deepcopy

      >>> a = [11,22]
      >>> b = (a,)
      >>> c = [b]
      >>> 
      >>> d = copy.deepcopy(c)
      >>> 
      >>> c
      [([11, 22],)]
      >>> d
      [([11, 22],)]
      >>> 
      >>> id(c)
      4528932680
      >>> id(d)
      4528761928
      >>> 
      >>> id(c[0])
      4528913040
      >>> id(d[0])
      4528913096
      >>> 
      >>> a.append(33)
      >>> 
      >>> c
      [([11, 22, 33],)]
      >>> d
      [([11, 22],)]
      >>> 
      
      copy.deepcopy
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。