欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用Pyrex來(lái)擴(kuò)展和加速Python程序的教程

 更新時(shí)間:2015年04月13日 12:02:21   投稿:goldensun  
這篇文章主要介紹了使用Pyrex來(lái)擴(kuò)展和加速Python程序的教程,來(lái)自IBM官方技術(shù)文檔,需要的朋友可以參考下

 Pyrex 是一種專(zhuān)門(mén)設(shè)計(jì)用來(lái)編寫(xiě) Python 擴(kuò)展模塊的語(yǔ)言。根據(jù) Pyrex Web 站點(diǎn)的介紹,“它被設(shè)計(jì)用來(lái)在友好易用的高級(jí) Python 世界和凌亂的低級(jí) C 世界之間搭建一個(gè)橋梁?!彪m然幾乎所有的 Python 代碼都可以作為有效的 Pyrex 代碼使用,但是您可以在 Pyrex 代碼中添加可選的靜態(tài)類(lèi)型聲明,從而使得這些聲明過(guò)的對(duì)象以 C 語(yǔ)言的速度運(yùn)行。
加速 Python

從某種意義上來(lái)說(shuō),Pyrex 只是不斷發(fā)展的 Python 類(lèi)語(yǔ)言系列的一個(gè)部分:Jython、IronPython、Prothon、Boo、Vyper(現(xiàn)在沒(méi)人用了)、Stackless Python(以一種方式)或 Parrot runtime(以另外一種方式)。按照語(yǔ)言的術(shù)語(yǔ)來(lái)說(shuō),Pyrex 本質(zhì)上是在 Python 中添加了類(lèi)型聲明。它的另外幾個(gè)變化沒(méi)有這么重要(不過(guò)對(duì) for 循環(huán)的擴(kuò)展很漂亮)。

然而,您真正希望使用 Pyrex 的原因是它編寫(xiě)的模塊比純 Python 運(yùn)行得更快,可能會(huì)快很多。

實(shí)際上,Pyrex 會(huì)從 Pyrex 代碼生成一個(gè) C 程序。中間文件 module.c 依然可以用于手工處理。然而對(duì)于“普通的” Pyrex 用戶(hù)來(lái)說(shuō),沒(méi)有什么理由需要修改所生成的 C 模塊。Pyrex 本身可以讓您訪問(wèn)那些對(duì)速度至關(guān)重要的 C 級(jí)代碼,而節(jié)省了編寫(xiě)內(nèi)存分配、回收、指針運(yùn)算、函數(shù)原型等的工作。Pyrex 還可以無(wú)縫地處理 Python 級(jí)對(duì)象的所有接口;通常它都是通過(guò)在必要的地方將變量聲明為 PyObject 結(jié)構(gòu)并使用 Python C-API 調(diào)用進(jìn)行內(nèi)存處理和類(lèi)型轉(zhuǎn)換而實(shí)現(xiàn)的。

對(duì)于大部分情況來(lái)說(shuō),Pyrex 不需要不斷對(duì)簡(jiǎn)單數(shù)據(jù)類(lèi)型變量進(jìn)行裝箱(box) 和 拆箱(unbox) 操作,因此速度比 Python 更快。例如,Python 中的 int 類(lèi)型是一個(gè)具有很多方法的對(duì)象。它有一個(gè)繼承樹(shù),自己有一個(gè)計(jì)算好的“方法解析順序(mothod resolution order,MRO)”。它有分配和回收方法可以用于內(nèi)存處理。它知道何時(shí)將自己轉(zhuǎn)換為一個(gè) long 類(lèi)型,以及如何對(duì)其他類(lèi)型的值進(jìn)行數(shù)值運(yùn)算。所有這些額外的功能都意味著在使用 int 對(duì)象進(jìn)行處理時(shí)需要經(jīng)過(guò)更多級(jí)的間接處理或條件檢查。另外一方面,C 或 Pyrex 的 int 變量只是內(nèi)存中各個(gè)位設(shè)置為 1 或 0 的一個(gè)區(qū)域。使用 C/Pyrex 的 int 類(lèi)型進(jìn)行處理不需要涉及 任何 間接操作或條件檢查。一個(gè) CPU “加”操作在硅芯片中就可以執(zhí)行完了。

在仔細(xì)選擇的情況中,Pyrex 模塊的速度可以比 Python 版本的相同模塊的運(yùn)行速度快 40 到 50 倍。但是與使用 C 本身 編寫(xiě)的模塊相比,Pyrex 版本的模塊幾乎都不會(huì)比 Python 版本的模塊更長(zhǎng),代碼更類(lèi)似于 Python,而不是 C。

當(dāng)然,當(dāng)您開(kāi)始談?wù)摷铀伲?lèi))Python 模塊時(shí),Pyrex 并不是惟一可用的工具。在 Python 開(kāi)發(fā)者的選擇中,也可以使用 Psyco。Psyco 可以保持代碼非常簡(jiǎn)短;它是(x86)機(jī)器代碼中的一個(gè) JIT Python 代碼編譯器。與 Pyrex 不同,Psyco 并不會(huì)精確地限定變量的類(lèi)型,而是根據(jù)數(shù)據(jù) 可能 是哪種類(lèi)型的每種假設(shè)為每個(gè) Python 代碼塊創(chuàng)建幾種可能的機(jī)器代碼。如果在一個(gè)給定的代碼段中數(shù)據(jù)是是簡(jiǎn)單類(lèi)型,例如 int,那么這段代碼(如果是一個(gè)循環(huán),這種情況就更為突出)就可以很快地運(yùn)行。例如,x 在一個(gè)執(zhí)行一百萬(wàn)次的循環(huán)中可以是 int 類(lèi)型,但是在循環(huán)結(jié)束時(shí)可以依然是一個(gè) float 類(lèi)型的值。Psyco 可以使用與在 Pyrex 中顯式指定的類(lèi)型相同的類(lèi)型來(lái)加速循環(huán)。

雖然 Pyrex 也并不難,但是 Psyco 更加簡(jiǎn)單易用。使用 Psyco 不過(guò)是在模塊的末尾加上幾行;實(shí)際上,如果加上正確的代碼,那么即使在 Psyco 不可用時(shí),模塊也可以同樣運(yùn)行(只是速度較慢)。
清單 1. 只有在 Psyco 可用時(shí)才使用 Psyco

# Import Psyco if available
try:
  import psyco
  psyco.full()
except ImportError:
  pass

要使用 Pyrex,需要對(duì)代碼進(jìn)行的修改會(huì)更多(但也不過(guò)是多一點(diǎn)而已),系統(tǒng)中還需要安裝一個(gè) C 編譯器,并正確對(duì)生成 Pyrex 模塊的系統(tǒng)進(jìn)行配置。雖然您 可以 分發(fā)二進(jìn)制的 Pyrex 模塊,但是為了能使您的模塊在其他地方也可以運(yùn)行,Python 的版本、架構(gòu)和終端用戶(hù)需要的優(yōu)化選項(xiàng)必須匹配。

速度初體驗(yàn)

我最近為 developerWorks 的文章 Beat spam using hashcash 創(chuàng)建了一個(gè)純 Python 的 hashcash 實(shí)現(xiàn),但是基本上來(lái)說(shuō),hashcash 是一種使用 SHA-1 提供 CPU 工作的技術(shù)。Python 有一個(gè)標(biāo)準(zhǔn)的模塊 sha,這使得編寫(xiě) hashcash 非常簡(jiǎn)單。

與我編寫(xiě)的 95% 的 Python 程序不同,hashcash 模塊緩慢的速度讓我心煩,至少有那么一點(diǎn)點(diǎn)心煩。按照設(shè)計(jì),這個(gè)協(xié)議就是要吃光所有的 CPU 周期,因此運(yùn)行效率非常關(guān)鍵。hashcash.c 的 ANSI C 二進(jìn)制文件運(yùn)行的速度是這個(gè) hashcash.py 腳本的 10 倍。而且啟用了 PPC/Altivec 的優(yōu)化后的 hashcash.c 二進(jìn)制文件的速度是普通的 ANSI C 版本的 4 倍(1Ghz 的 G4/Altivec 在處理 hashcash/SHA 操作時(shí)的速度相當(dāng)于 3Ghz 的 Pentium4?/MMX;G5 的速度會(huì)更快)。因此在我的 TiPowerbook 上的測(cè)試顯示,這個(gè)模塊的速度比優(yōu)化后的 C 版本速度慢 40 倍(不過(guò)在 x86 上的差距沒(méi)有這么大)。

由于這個(gè)模塊的運(yùn)行速度很慢,可能 Pyrex 會(huì)是一個(gè)比較好的加速方法。至少我認(rèn)為是如此?!癙yrex 化” hashcash.py 的第一件事情(當(dāng)然是在安裝 Pyrex 之后)是簡(jiǎn)單地將其拷貝為 hashcash_pyx.pyx,并試圖這樣處理:

$ pyrexc hashcash_pyx.pyx

創(chuàng)建二進(jìn)制模塊

運(yùn)行這個(gè)命令會(huì)生成一個(gè) hashcash.c 文件(這會(huì)對(duì)源文件進(jìn)行一些微小的改動(dòng))。不幸的是,調(diào)整 gcc 開(kāi)關(guān)剛好適合我的平臺(tái)需要點(diǎn)技巧,因此我決定采用推薦的捷徑,讓 distutils 為我做一些工作。標(biāo)準(zhǔn)的 Python 安裝知道如何在模塊安裝過(guò)程中使用本地的 C 編譯器,以及如何使用 distutils 來(lái)簡(jiǎn)化 Pyrex 模塊的共享。我創(chuàng)建了一個(gè) setup_hashcash.py 腳本,如下所示:
清單 2. setup_hashcash.py 腳本

from distutils.core import setup
from distutils.extension import Extension
from Pyrex.Distutils import build_ext
setup(
 name = "hashcash_pyx",
 ext_modules=[
  Extension("hashcash_pyx", ["hashcash_pyx.pyx"], libraries = [])
  ],
 cmdclass = {'build_ext': build_ext}
)

運(yùn)行下面的命令,完整地編譯一個(gè)基于 C 的擴(kuò)展模塊 hashcash:

$ python2.3 prime_setup.py build_ext --inplace

代碼修改

我把從 hashcash.pyx 生成基于 C 的模塊的工作有些簡(jiǎn)化了。實(shí)際上,我需要對(duì)源代碼進(jìn)行兩處修改;通過(guò)查找 pyrexc 抱怨的位置來(lái)找到要修改的位置。在代碼中,我使用了一個(gè)不支持的列表,將其放入一個(gè)普通的 for 循環(huán)。這非常簡(jiǎn)單。我還將增量賦值從 counter+=1 修改為 counter=counter+1。

就這么多了。這就是我的第一個(gè) Pyrex 模塊。

測(cè)試速度

為了可以簡(jiǎn)單地測(cè)試要開(kāi)發(fā)的模塊的速度提高情況,我編寫(xiě)了一個(gè)簡(jiǎn)單的測(cè)試程序來(lái)運(yùn)行不同版本的模塊:
清單 3. 測(cè)試程序 hashcash_test.py

#!/usr/bin/env python2.3
import time, sys, optparse
hashcash = __import__(sys.argv[1])
start = time.time()
print hashcash.mint('mertz@gnosis.cx', bits=20)
timer = time.time()-start
sys.stderr.write("%0.4f seconds (%d hashes per second)\n" %
    (timer, hashcash.tries[0]/timer))

令人興奮的是,我決定來(lái)看一下只通過(guò) Pyrex 編譯可以怎樣提高速度。注意在下面所有的例子中,真實(shí)的時(shí)間變化很大,都是隨機(jī)的。我們要看的內(nèi)容是“hashes per second”,它可以精確可靠地測(cè)量速度。因此比較一下純粹的 Python 和 Pyrex:
清單 4. 純 Python 和 “純 Pyrex”的比較

$ ./hashcash_test.py hashcash
1:20:041003:mertz@gnosis.cx::I+lyNUpV:167dca
13.7879 seconds (106904 hashes per second)
$ ./hashcash_test.py hashcash_pyx > /dev/null
6.0695 seconds (89239 hashes per second)

噢!使用 Pyrex 幾乎慢了 20%。這并不是我期望的?,F(xiàn)在應(yīng)該來(lái)分析一下代碼可能加速的地方了。下面這個(gè)簡(jiǎn)短的函數(shù)會(huì)試圖消耗所有的時(shí)間:
清單 5. hashcash.py 中的函數(shù)

def _mint(challenge, bits):
  "Answer a 'generalized hashcash' challenge'"
  counter = 0
  hex_digits = int(ceil(bits/4.))
  zeros = '0'*hex_digits
  hash = sha
  while 1:
    digest = hash(challenge+hex(counter)[2:]).hexdigest()
    if digest[:hex_digits] == zeros:
      tries[0] = counter
      return hex(counter)[2:]
    counter += 1

我需要利用 Pyrex 變量聲明的優(yōu)點(diǎn)來(lái)進(jìn)行加速。有些變量顯然是整數(shù),另外一些變量顯然是字符串 —— 我們可以指定這些類(lèi)型。在進(jìn)行修改時(shí),我將使用 Pyrex 的經(jīng)過(guò)改進(jìn)的 for 循環(huán):
清單 6. 經(jīng)過(guò)最低限度 Pyrex 改進(jìn)的 mint 函數(shù)

cdef _mint(challenge, int bits):
  # Answer a 'generalized hashcash' challenge'"
  cdef int counter, hex_digits, i
  cdef char *digest
  hex_digits = int(ceil(bits/4.))
  hash = sha
  for counter from 0 <= counter < sys.maxint:
    py_digest = hash(challenge+hex(counter)[2:]).hexdigest()
    digest = py_digest
    for i from 0 <= i < hex_digits:
      if digest[i] != c'0': break
    else:
      tries[0] = counter
      return hex(counter)[2:]

到現(xiàn)在為止一切都非常簡(jiǎn)單。我只聲明了早已知道的一些變量類(lèi)型,并使用最干凈的 Pyrex counter 循環(huán)。一個(gè)小技巧是將 py_digest(一個(gè) Python 字符串)賦值給 digest(一個(gè) C/Pyrex 字符串),目的是確定其類(lèi)型。經(jīng)過(guò)實(shí)驗(yàn),我還發(fā)現(xiàn)循環(huán)字符串比較操作速度都非??臁_@些會(huì)帶來(lái)什么好處呢?
清單 7. Pyrex 化 mint 函數(shù)的速度結(jié)果

$ ./hashcash_test.py hashcash_pyx2 >/dev/null
20.3749 seconds (116636 hashes per second)

這下好多了。我已經(jīng)對(duì)原有的 Python 進(jìn)行了一些細(xì)微的改進(jìn),這可以稍微提高最初的 Pyrex 模塊的速度。不過(guò)效果還不明顯,僅僅提高了很少的百分比。
剖析

有些東西似乎不對(duì)。速度提高幾個(gè)百分比和 Pyrex 主頁(yè)(以及很多 Pyrex 用戶(hù))那樣提高 40 倍有很大的差距?,F(xiàn)在應(yīng)該來(lái)看一下 這個(gè) Python _mint() 函數(shù)中 哪些 地方真正消耗了時(shí)間。有一個(gè) quick 腳本(此處沒(méi)有給出)可以分解復(fù)雜操作 sha(challenge+hex(counter)[2:]).hexdigest():
清單 8. hashcash 的 mint 函數(shù)的時(shí)間消耗

1000000 empty loops:   0.559
------------------------------
1000000 sha()s:     2.332
1000000 hex()[2:]s:   3.151
  just hex()s:     <2.471>
1000000 concatenations: 0.855
1000000 hexdigest()s:  3.742
------------------------------
Total:         10.079

顯然,我并不能將這個(gè)循環(huán)從 _mint() 函數(shù)中刪除。雖然 Pyrex 改進(jìn)后的 for 循環(huán)可能有一點(diǎn)加速,但是整個(gè)函數(shù)主要是一個(gè)循環(huán)。我也不能刪除對(duì) sha() 的調(diào)用,除非要使用 Pyrex 重新實(shí)現(xiàn) SHA-1(即使我要這樣做,也沒(méi)有自信自己可以比 Python 標(biāo)準(zhǔn)的 sha 模塊的作者做得更好)。而且,如果我希望得到一個(gè) sha.SHA 對(duì)象的 hash 值,就只能調(diào)用 .hexdigest() 或 .digest();前者的速度更快。

現(xiàn)在真正要解決的是 hex() 對(duì) counter 變量的轉(zhuǎn)換,以及結(jié)果中時(shí)間片的消耗情況。我可能需要使用 Pyrex/C 的字符串連接操作,而不是 Python 的字符串對(duì)象。然而,我見(jiàn)過(guò)的惟一一種避免 hex() 轉(zhuǎn)換的方法是手工在嵌套循環(huán)之外構(gòu)建一個(gè)后綴。雖然這樣做可以避免 int 到 char 類(lèi)型的轉(zhuǎn)換,但是需要生成更多代碼:
清單 9. 完全 Pyrex 優(yōu)化過(guò)的 mint 函數(shù)

cdef _mint(char *challenge, int bits):
  cdef int hex_digits, i0, i1, i2, i3, i4, i5
  cdef char *ab, *digest, *trial, *suffix
  suffix = '******'
  ab = alphabet
  hex_digits = int(ceil(bits/4.))
  hash = sha
  for i0 from 0 <= i0 < 55:
    suffix[0] = ab[i0]
    for i1 from 0 <= i1 < 55:
      suffix[1] = ab[i1]
      for i2 from 0 <= i2 < 55:
        suffix[2] = ab[i2]
        for i3 from 0 <= i3 < 55:
          suffix[3] = ab[i3]
          for i4 from 0 <= i4 < 55:
            suffix[4] = ab[i4]
            for i5 from 0 <= i5 < 55:
              suffix[5] = ab[i5]
              py_digest = hash(challenge+suffix).hexdigest()
              digest = py_digest
              for i from 0 <= i < hex_digits:
                if digest[i] != c'0': break
              else:
                return suffix

雖然這個(gè) Pyrex 函數(shù)看起來(lái)仍然比對(duì)應(yīng)的 C 函數(shù)更加簡(jiǎn)單易讀,但是它實(shí)際上最初的純 Python 的版本更為復(fù)雜。通過(guò)這種方式,在純 Python 中展開(kāi)后綴生成與最初的版本相比會(huì)對(duì)總體速度有些負(fù)面的影響。在 Pyrex 中,正如您期望的一樣,這些嵌套的循環(huán)都是很少花費(fèi)時(shí)間的,因而我節(jié)省了轉(zhuǎn)換和分時(shí)調(diào)度的代價(jià):
清單 10. mint 函數(shù) Pyrex 化優(yōu)化后的速度結(jié)果

$ ./hashcash_test.py hashcash_pyx3 >/dev/null
13.2270 seconds (166125 hashes per second)

當(dāng)然,這比我開(kāi)始的時(shí)候好多了。但是速度提高也不過(guò)是兩倍。大部分時(shí)間的問(wèn)題是(此處也是)消耗了太多的時(shí)間在對(duì) Python 庫(kù)的調(diào)用上,而我并不能對(duì)這些調(diào)用編寫(xiě)代碼來(lái)提高速度。
令人失望的比較

速度提高 50% 到 60% 似乎是值得的。達(dá)到這個(gè)目標(biāo)我并沒(méi)有編寫(xiě) 多少 代碼。但是如果您認(rèn)為是在原來(lái)的 Python 版本中添加 兩條 語(yǔ)句 import psyco;psyco.bind(_mint),那么這種加速方法就不會(huì)給您多深的印象:
清單 11. mint 函數(shù) Psyco 化的加速結(jié)果

$ ./hashcash_test.py hashcash_psyco >/dev/null
15.2300 seconds (157550 hashes per second)

換而言之,Psyco 之不過(guò)添加了兩行通用的代碼,就幾乎能實(shí)現(xiàn)相同的目標(biāo)。當(dāng)然,Psyco 只能用于 x86 平臺(tái),而 Pyrex 可以在具有 C 編譯器的所有環(huán)境上執(zhí)行。但是對(duì)于這個(gè)特定的例子來(lái)說(shuō),os.popen('hashcash -m '+options) 的速度會(huì)比 Pyrex 和 Psyco 都快很多倍(當(dāng)然,假設(shè)可以使用 C 工具 hashcash)。

 

相關(guān)文章

  • 超簡(jiǎn)單的scrapy實(shí)現(xiàn)ip動(dòng)態(tài)代理與更換ip的方法實(shí)現(xiàn)

    超簡(jiǎn)單的scrapy實(shí)現(xiàn)ip動(dòng)態(tài)代理與更換ip的方法實(shí)現(xiàn)

    這篇文章主要介紹了超簡(jiǎn)單的scrapy實(shí)現(xiàn)ip動(dòng)態(tài)代理與更換ip的方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • pd.to_datetime中時(shí)間object轉(zhuǎn)換datetime實(shí)例

    pd.to_datetime中時(shí)間object轉(zhuǎn)換datetime實(shí)例

    本文主要介紹了pd.to_datetime中時(shí)間object轉(zhuǎn)換datetime實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • django 消息框架 message使用詳解

    django 消息框架 message使用詳解

    這篇文章主要介紹了django 消息框架 message使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • Python標(biāo)準(zhǔn)庫(kù):內(nèi)置函數(shù)max(iterable, *[, key, default])說(shuō)明

    Python標(biāo)準(zhǔn)庫(kù):內(nèi)置函數(shù)max(iterable, *[, key, default])說(shuō)明

    這篇文章主要介紹了Python標(biāo)準(zhǔn)庫(kù):內(nèi)置函數(shù)max(iterable, *[, key, default])說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-04-04
  • python的Jenkins接口調(diào)用方式

    python的Jenkins接口調(diào)用方式

    這篇文章主要介紹了python的Jenkins接口調(diào)用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-05-05
  • Python 3.8新特征之a(chǎn)syncio REPL

    Python 3.8新特征之a(chǎn)syncio REPL

    我最近都在寫(xiě)一些Python 3.8的新功能介紹的文章,在自己的項(xiàng)目中也在提前體驗(yàn)新的Python版本。這篇文章主要介紹了Python 3.8新特征之a(chǎn)syncio REPL,需要的朋友可以參考下
    2019-05-05
  • Selenium(Python web測(cè)試工具)基本用法詳解

    Selenium(Python web測(cè)試工具)基本用法詳解

    這篇文章主要介紹了Selenium(Python web測(cè)試工具)基本用法,結(jié)合實(shí)例形式分析了Selenium的基本安裝、簡(jiǎn)單使用方法及相關(guān)操作技巧,需要的朋友可以參考下
    2018-08-08
  • python中使用序列的方法

    python中使用序列的方法

    這篇文章主要介紹了python中使用序列的方法,較為詳細(xì)的分析了Python序列的原理與使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-08-08
  • 用python如何繪制表格不同顏色的excel

    用python如何繪制表格不同顏色的excel

    做數(shù)據(jù)分析的時(shí)候,用到了對(duì)Excel中的數(shù)據(jù)進(jìn)行顯示處理,能更直觀的了解數(shù)據(jù),所以下面這篇文章主要給大家介紹了關(guān)于利用python如何繪制表格不同顏色excel的相關(guān)資料,需要的朋友可以參考下
    2021-11-11
  • 關(guān)于django python manage.py startapp 應(yīng)用名出錯(cuò)異常原因解析

    關(guān)于django python manage.py startapp 應(yīng)用名出錯(cuò)異常原因解析

    這篇文章主要介紹了關(guān)于django python manage.py startapp 應(yīng)用名出錯(cuò)異常原因解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12

最新評(píng)論