色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

將string轉(zhuǎn)換成int/long的步驟分享

jf_ro2CN3Fa ? 來源:Kirito的技術(shù)分享 ? 2023-03-17 17:15 ? 次閱讀

在很多追求性能的程序挑戰(zhàn)賽中,經(jīng)常會遇到一個操作:將 String 轉(zhuǎn)換成 Integer/Long。如果你沒有開發(fā)過高并發(fā)的系統(tǒng),或者沒有參加過任何性能挑戰(zhàn)賽,可能會有這樣的疑問:這有啥好講究的,Integer.valueOf/Long.valueOf 又不是不能用。實際上,很多內(nèi)置的轉(zhuǎn)換工具類只滿足了功能性的需求,在高并發(fā)場景下,可能會是熱點方法,成為系統(tǒng)性能的瓶頸。

問題提出

假設現(xiàn)在有一些文本信息固定長度為 16 位 ,例如下文給出的時間戳,需要盡可能快地解析這些時間戳

timestamp
1585201087123567
1585201087123585
1585201087123621

方法體如下所示:

std::uint64_tparse_timestamp(std::string_views)
{
//???
}

問題提出后,大家不妨先思考下,如果是你,你會采取什么方案呢?帶著這樣的思考,我們進入下面的一個個方案。

Native 方案

我們有哪些現(xiàn)成的轉(zhuǎn)換方案呢?

繼承自 C 的 std::atoll

std::stringstream

C++17 提供的 charconv

boost::qi

評測程序采用 Google Benchmark 進行對比評測。同時,我們以不做任何轉(zhuǎn)換的方案來充當 baseline,以供對比。(baseline 方案在底層,相當于將數(shù)值放進來了寄存器中,所以命名成了 BM_mov)

下面給出的評測代碼不是那么地關(guān)鍵,只是為了給大家展示評測是如何運行的。

staticvoidBM_mov(benchmark::State&state){
for(auto_:state){
benchmark::DoNotOptimize(1585201087123789);
}
}

staticvoidBM_atoll(benchmark::State&state){
for(auto_:state){
benchmark::atoll(example_timestamp));
}
}

staticvoidBM_sstream(benchmark::State&state){
std::stringstreams(example_timestamp);
for(auto_:state){
s.seekg(0);
std::uint64_ti=0;
s>>i;
benchmark::DoNotOptimize(i);
}
}
staticvoidBM_charconv(benchmark::State&state){
autos=example_timestamp;
for(auto_:state){
std::uint64_tresult=0;
std::from_chars(s.data(),s.data()+s.size(),result);
benchmark::DoNotOptimize(result);
}
}

staticvoidBM_boost_spirit(benchmark::State&state){
usingboost::parse;
for(auto_:state){
std::uint64_tresult=0;
parse(s.data(),s.data()+s.size(),result);
benchmark::DoNotOptimize(result);
}
}
42cb56a4-c4a2-11ed-bfe3-dac502259ad0.pngNative

可以發(fā)現(xiàn) stringstream 表現(xiàn)的非常差。當然,這并不是一個公平的比較,但從測評結(jié)果來看,使用 stringstream 來實現(xiàn)數(shù)值轉(zhuǎn)換相比 baseline 慢了 391 倍。相比之下, 和 boost::spirit 表現(xiàn)的更好。

既然我們已經(jīng)知道了目標字符串包含了要解析的數(shù)字,而且不需要做任何的數(shù)值校驗,基于這些前提,我們可以思考下,還有更快的方案嗎?

Naive 方案

我們可以通過一個再簡單不過的循環(huán)方案,一個個地解析字符。

inlinestd::uint64_tparse_naive(std::string_views)noexcept
{
std::uint64_tresult=0;
for(chardigit:s)
{
result*=10;
result+=digit-'0';
}
returnresult;
}
42ddfaf2-c4a2-11ed-bfe3-dac502259ad0.png

Naive

雖然這層 for 循環(huán)看起來呆呆的,但如果這樣一個呆呆的解決方案能夠擊敗標準庫實現(xiàn),何樂而不為呢?前提是,標準庫的實現(xiàn)考慮了異常場景,做了一些校驗,這種 for 循環(huán)寫法的一個前提是,我們的輸入一定是合理的。

之前我的文章也提到過這個方案。顯然, naive 的方案之后還會有更優(yōu)的替代方案。

循環(huán)展開方案

記得我們在文章的開頭加了一個限定,限定了字符串長度固定是 16 位,所以循環(huán)是可以被省略的,循環(huán)展開之后,方案可以更快。

inlinestd::uint64_tparse_unrolled(std::string_views)noexcept
{
std::uint64_tresult=0;

result+=(s[0]-'0')*1000000000000000ULL;
result+=(s[1]-'0')*100000000000000ULL;
result+=(s[2]-'0')*10000000000000ULL;
result+=(s[3]-'0')*1000000000000ULL;
result+=(s[4]-'0')*100000000000ULL;
result+=(s[5]-'0')*10000000000ULL;
result+=(s[6]-'0')*1000000000ULL;
result+=(s[7]-'0')*100000000ULL;
result+=(s[8]-'0')*10000000ULL;
result+=(s[9]-'0')*1000000ULL;
result+=(s[10]-'0')*100000ULL;
result+=(s[11]-'0')*10000ULL;
result+=(s[12]-'0')*1000ULL;
result+=(s[13]-'0')*100ULL;
result+=(s[14]-'0')*10ULL;
result+=(s[15]-'0');

returnresult;
}
42e4c012-c4a2-11ed-bfe3-dac502259ad0.png

unrolled

關(guān)于循環(huán)展開為什么會更快,可以參考我過去關(guān)于 JMH 的文章。

byteswap 方案

先思考下,如果繼續(xù)圍繞上述的方案進行,我們可能只有兩個方向:

并發(fā)執(zhí)行加法和乘法計算,但這種 CPU 操作似乎又不能通過多線程之類的手段進行加速,該如何優(yōu)化是個問題

將乘法和加法運算轉(zhuǎn)換成位運算,獲得更快的 CPU 執(zhí)行速度,但如果轉(zhuǎn)換又是個問題

相信讀者們都會有這樣的疑問,那我們繼續(xù)帶著這樣疑問往下看原作者的優(yōu)化思路是什么。

緊接著上述的循環(huán)展開方案,將 “1234” 解析為 32 位整數(shù)對應的循環(huán)展開操作繪制為圖,過程如下:

42ff9a9a-c4a2-11ed-bfe3-dac502259ad0.png

Unrolled solution graph

我們可以看到,乘法和加法的操作次數(shù)跟字符的數(shù)量是線性相關(guān)的。由于每一次乘法都是由不同的乘數(shù)進行,所以我們不能只乘“一次”,在乘法的最后,我們還需要將所有結(jié)果相加。乍一看,好像很難優(yōu)化。

下面的優(yōu)化技巧,需要一些操作系統(tǒng)、編譯原理相關(guān)的知識作為輔助,你需要了解 byteswap 這個系統(tǒng)調(diào)用,了解大端序和小端序的字節(jié)序表示方法(后面我也會分享相關(guān)的文章),如果你不關(guān)心這些細節(jié),也可以直接跳到本段的最后,直接看結(jié)論。

理解清楚下圖的含義,需要理解幾個概念:

字符 1 對應的 ascii 值是 31,相應的 2 對應 32,4 對應 34

在小端序機器上(例如 x86),字符串是以大端序存儲的,而 Integer 是以小端序存儲的

byteswap 可以實現(xiàn)字節(jié)序調(diào)換

4310781a-c4a2-11ed-bfe3-dac502259ad0.png

byteswap

上圖展示了十六進制表示下的轉(zhuǎn)換過程,可以在更少的操作下達到最終的解析狀態(tài)。

將上圖的流程使用 C++ 來實現(xiàn),將 String 重新解釋為 Integer,必須使用 std::memcpy(避免命名沖突),執(zhí)行相減操作,然后通過編譯器內(nèi)置的 __builtin_bswap64 在一條指令中交換字節(jié)。到目前為止,這是最快的一個優(yōu)化。

template
inlineTget_zeros_string()noexcept;

template<>
inlinestd::uint64_tget_zeros_string()noexcept
{
std::uint64_tresult=0;
constexprcharzeros[]="00000000";
std::memcpy(&result,zeros,sizeof(result));
returnresult;
}

inlinestd::uint64_tparse_8_chars(constchar*string)noexcept
{
std::uint64_tchunk=0;
std::memcpy(&chunk,string,sizeof(chunk));
chunk=__builtin_bswap64(chunk-get_zeros_string());

//...
}

我們看上去得到了想要的結(jié)果,但是這個方案從時間復雜度來看,仍然是 O(n) 的,是否可以在這個方案的基礎上,繼續(xù)進行優(yōu)化呢?

分治方案

從最初的 Native 方案,到上一節(jié)的 byteswap 方案,我們都只是優(yōu)化了 CPU 操作,并沒有優(yōu)化復雜度,既然不滿足于 O(n),那下一個復雜度可能性是什么?O(logn)!我們可以將每個相鄰的數(shù)字組合成一對,然后將每對數(shù)字繼續(xù)組合成一組四個,依此類推,直到我們得到整個整數(shù)。

如何同時處理鄰近的數(shù)字,這是讓算法跑進 O(logn) 的關(guān)鍵

該方案的關(guān)鍵之處在于:將偶數(shù)位的數(shù)字乘以 10 的冪,并且單獨留下奇數(shù)位的數(shù)字。這可以通過位掩碼(bitmasking)來實現(xiàn)

433033bc-c4a2-11ed-bfe3-dac502259ad0.png

分治方案

通過 bitmasking,我們可以一次對多個數(shù)字進行操作,將它們組合成一個更大的組合

通過使用這個掩碼技巧來實現(xiàn)前文提到的 parse_8_chars 函數(shù)。使用 bitmasking 的另一好處在于,我們不用減去 '0' ,因為位掩碼的副作用,使得我們正好可以省略這一步。

inlinestd::uint64_tparse_8_chars(constchar*string)noexcept
{
std::uint64_tchunk=0;
std::memcpy(&chunk,string,sizeof(chunk));

//1-bytemasktrick(workson4pairsofsingledigits)
std::uint64_tlower_digits=(chunk&0x0f000f000f000f00)>>8;
std::uint64_tupper_digits=(chunk&0x000f000f000f000f)*10;
chunk=lower_digits+upper_digits;

//2-bytemasktrick(workson2pairsoftwodigits)
lower_digits=(chunk&0x00ff000000ff0000)>>16;
upper_digits=(chunk&0x000000ff000000ff)*100;
chunk=lower_digits+upper_digits;

//4-bytemasktrick(worksonpairoffourdigits)
lower_digits=(chunk&0x0000ffff00000000)>>32;
upper_digits=(chunk&0x000000000000ffff)*10000;
chunk=lower_digits+upper_digits;

returnchunk;
}

trick 方案

綜合前面兩節(jié),解析 16 位的數(shù)字,我們將它分成兩個 8 字節(jié)的塊,運行剛剛編寫的 parse_8_chars,并對其進行基準測試!

inlinestd::uint64_tparse_trick(std::string_views)noexcept
{
std::uint64_tupper_digits=parse_8_chars(s.data());
std::uint64_tlower_digits=parse_8_chars(s.data()+8);
returnupper_digits*100000000+lower_digits;
}

staticvoidBM_trick(benchmark::State&state){
for(auto_:state){
benchmark::DoNotOptimize(parse_trick(example_stringview));
}
}
43907c04-c4a2-11ed-bfe3-dac502259ad0.png

trick

看上去優(yōu)化的不錯,我們將循環(huán)展開方案的基準測試優(yōu)化了近 56% 的性能。能做到這一點,主要得益于我們手動進行一系列 CPU 優(yōu)化的操作,雖然這些并不是特別通用的技巧。

這樣算不算開了個不好的頭呢?我們看起來對 CPU 操作干預地太多了,或許我們應該放棄這些優(yōu)化,讓 CPU 自由地飛翔。

SIMD trick 方案

你是不是以為上面已經(jīng)是最終方案了呢?不,優(yōu)化還剩最后一步。

我們已經(jīng)得到了一個結(jié)論

同時組合多組數(shù)字以實現(xiàn) O(logn) 復雜度

如果有 16 個字符或 128 位的字符串要解析,還可以使用 SIMD。感興趣的讀者可以參考SIMD stands for Single Instruction Multiple Data。IntelAMD CPU 都支持 SSE 和 AVX 指令,并且它們通常使用更寬的寄存器。

SIMA 簡單來說就是一組 CPU 的擴展指令,可以通過調(diào)用多組寄存器實現(xiàn)并行的乘法運算,從而提升系統(tǒng)性能。我們一般提到的向量化運算就是 SIMA。

讓我們先設置 16 個字節(jié)中的每一個數(shù)字:

inlinestd::uint64_tparse_16_chars(constchar*string)noexcept
{
autochunk=_mm_lddqu_si128(
reinterpret_cast(string)
);
autozeros=_mm_set1_epi8('0');
chunk=chunk-zeros;

//...
}

現(xiàn)在,主角變成了 madd 該系統(tǒng)調(diào)用。這些 SIMD 函數(shù)與我們使用位掩碼技巧所做的操作完全一樣——它們采用同一個寬寄存器,將其解釋為一個由較小整數(shù)組成的向量,每個乘以一個特定的乘數(shù),然后將相鄰位的結(jié)果相加到一個更寬的整數(shù)向量中。所有操作一步完成。

//The1-byte"trick"inoneinstruction
constautomult=_mm_set_epi8(
1,10,1,10,1,10,1,10,1,10,1,10,1,10,1,10
);
chunk=_mm_maddubs_epi16(chunk,mult);

2 字節(jié)方案其實還有另一條指令,但不幸的是我并沒有找到 4 字節(jié)方案的指令,還是需要兩條指令。這是完整的 parse_16_chars 方案:

inlinestd::uint64_tparse_16_chars(constchar*string)noexcept
{
autochunk=_mm_lddqu_si128(
reinterpret_cast(string)
);
autozeros=_mm_set1_epi8('0');
chunk=chunk-zeros;

{
constautomult=_mm_set_epi8(
1,10,1,10,1,10,1,10,1,10,1,10,1,10,1,10
);
chunk=_mm_maddubs_epi16(chunk,mult);
}
{
constautomult=_mm_set_epi16(1,100,1,100,1,100,1,100);
chunk=_mm_madd_epi16(chunk,mult);
}
{
chunk=_mm_packus_epi32(chunk,chunk);
constautomult=_mm_set_epi16(0,0,0,0,1,10000,1,10000);
chunk=_mm_madd_epi16(chunk,mult);
}

return((chunk[0]&0xffffffff)*100000000)+(chunk[0]>>32);
}
43a7729c-c4a2-11ed-bfe3-dac502259ad0.png

SIMD trick

0.75 nanoseconds ! 是不是大吃一驚呢.

總結(jié)

43b09cfa-c4a2-11ed-bfe3-dac502259ad0.png

整體對比

有人可能會問,你為啥要用 C++ 來介紹下,不能用 Java 嗎?我再補充下,本文的測試結(jié)論,均來自于老外的文章,文章出處見開頭,其次,本文的后半部分的優(yōu)化,都是基于一些系統(tǒng)調(diào)用,和 CPU 指令的優(yōu)化,這些在 C++ 中實現(xiàn)起來方便一些,Java 只能走系統(tǒng)調(diào)用。

在最近過去的性能挑戰(zhàn)賽中,由于限定了不能使用 JNI,使得選手們只能將方案止步于循環(huán)展開方案,試想一下,如果允許走系統(tǒng)調(diào)用,加上比賽中字符串也基本是固定的長度,完全可以采用 SIMD 的 trick 方案,String 轉(zhuǎn) Long 的速度會更快。

polardb優(yōu)化點

實際上,在之前 polarDB 的比賽中,普哥就給我介紹過 bswap 的向量化方案,這也是為啥 Java 方案就是比 C++ 方案遜色的原因之一,C++ 在執(zhí)行一些 CPU 指令集以及系統(tǒng)調(diào)用上,比 Java 方便很多。

如何看待這一系列的優(yōu)化呢?從 std::stringstream 的 86.23 到 sima trick 方案的 0.75,這個優(yōu)化的過程是令人興奮的,但我們也發(fā)現(xiàn),越往后,越是用到一些底層的優(yōu)化技巧,正如方案中的 trick 而言,適用性是有限的。也有一種聲音是在說:花費這么大精力去優(yōu)化,為啥不去寫匯編呢?這又回到了“優(yōu)化是萬惡之源”這個話題。在業(yè)務項目中,可能你不用過多關(guān)注 String 是如何轉(zhuǎn)換為 Long 和 Integer 的,可能 Integer.valueOf 和 Long.valueOf 就可以滿足你的訴求,但如果你是一個需要大數(shù)據(jù)解析系統(tǒng),String 轉(zhuǎn)換是系統(tǒng)的瓶頸之一,相信本文的方案會給你一定的啟發(fā)。

另外對于 SIMD 這些方案,我想再多說一句。其實一些性能挑戰(zhàn)賽進行到最后,大家的整體方案其實都相差無幾,無非是參數(shù)差異,因為比賽場景通常不會太復雜,最后前幾名的差距,就是在一些非常小的細節(jié)上。正如 SIMA 提供的向量化運算等優(yōu)化技巧,它就是可以幫助你比其他人快個幾百毫秒,甚至 1~2s。這時候你會感嘆,原來我跟大神的差距,就是在這些細節(jié)上。但反觀整個過程,似乎這些優(yōu)化并不能幫助程序設計競賽發(fā)揮更大的能量,一個比賽如果只能依靠 CPU 優(yōu)化來實現(xiàn)區(qū)分度,我覺得一定不是成功的。所以,對于主辦方而言,禁用掉一些類庫,其實有效的避免了內(nèi)卷,于參賽者而言,算是一種減負了。希望以后的比賽也都朝著讓選手花更多精力去優(yōu)化方案,而不是優(yōu)化通用的細節(jié)上。

再回到 String 解析成 Long/Integer 的話題上。在實際使用時,大家也不用避諱繼續(xù)使用 Integer.valueOf 或者 Long.valueOf,大多數(shù)情況下,這不是系統(tǒng)的瓶頸。而如果你恰好在某些場景下遇到了 String 轉(zhuǎn)換的瓶頸,希望本文能夠幫到你。





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5357

    瀏覽量

    120637
  • SIMD
    +關(guān)注

    關(guān)注

    0

    文章

    35

    瀏覽量

    10308
  • C++語言
    +關(guān)注

    關(guān)注

    0

    文章

    147

    瀏覽量

    7008

原文標題:如何更快地將string轉(zhuǎn)換成int/long

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    protel轉(zhuǎn)換成powerpcb powerpcb轉(zhuǎn)換成protel的方法及步驟.pdf

    protel轉(zhuǎn)換成powerpcb powerpcb轉(zhuǎn)換成protel的方法及步驟.pdf 
    發(fā)表于 05-11 20:40

    怎么信號轉(zhuǎn)換成數(shù)組

    新手一個,RT,求教怎么信號轉(zhuǎn)換成數(shù)組,然后作傅立葉變換,得到幅度響應和相位響應。
    發(fā)表于 05-27 20:52

    pdf轉(zhuǎn)換成jpg格式的快速轉(zhuǎn)換方法

    pdf轉(zhuǎn)換成jpg。  這里向大家推薦一個非常簡單而又實用的方法,那就是使用迅捷PDF在線轉(zhuǎn)換器這個軟件就可以搞定了。這款軟件可以完美的中文支持和原始版面轉(zhuǎn)換,基本做到了百分百的原
    發(fā)表于 10-28 11:27

    long double to string函數(shù)找不到本地支持

    long double時,但沒有任何正式文檔,我不能接受它作為一個可行的解決方案。有人遇到過支持長雙倍的函數(shù),并將其轉(zhuǎn)換成一組ASCII字符,反之亦然?謝謝! 以上來自于百度翻譯 以下為原文 Hi,I
    發(fā)表于 11-02 14:58

    如何浮點轉(zhuǎn)換成PSOC5上的字符串?

    缺氧缺血性腦病,有沒有人知道如何浮點轉(zhuǎn)換成PSOC5(GCC編譯器)上的字符串?我想把浮點轉(zhuǎn)換成字符串,這樣我就可以在我的GLCD上顯示,它具有只顯示字符串類型的庫函數(shù)。 以上來自于百度翻譯
    發(fā)表于 03-28 06:55

    如何IEEE754雙字符串轉(zhuǎn)換成十進制字符串

    接近一千位)。通過使用Tom St Denis編寫的一個免費提供的多精度整數(shù)庫,我編寫了對該庫的擴展,以64位浮點數(shù)轉(zhuǎn)換成十進制字符串。該函數(shù)使用查找表(快速但冗長)浮點數(shù)轉(zhuǎn)換為任
    發(fā)表于 07-23 11:39

    如果float轉(zhuǎn)換成char類型為什么會提示報錯

    怎樣通過sprintffloat轉(zhuǎn)換成string類型的呢?如果float轉(zhuǎn)換成char類型為什么會提示報錯?有何解決辦法?
    發(fā)表于 12-01 07:37

    怎樣通過IC轉(zhuǎn)換MIPI轉(zhuǎn)換成LVDS呢

    怎樣通過IC轉(zhuǎn)換MIPI轉(zhuǎn)換成LVDS呢?MIPI轉(zhuǎn)LVDS調(diào)試的步驟有哪些呢?如何去完成呢?
    發(fā)表于 03-07 06:37

    怎么把int類型的數(shù)據(jù)轉(zhuǎn)換成字符串?

    怎么把 int 類型的數(shù)據(jù)轉(zhuǎn)換成字符串: 看項目有用 micrilib,itoa() 函數(shù) 和 sprintf() 能不能用呢?怎么用 比如把 int a=10;轉(zhuǎn)換成字符串 char
    發(fā)表于 11-01 08:27

    如何一個INT型數(shù)據(jù)轉(zhuǎn)換成2個CHAR型數(shù)據(jù)?

    如何一個INT型數(shù)據(jù)轉(zhuǎn)換成2個CHAR型數(shù)據(jù)?
    發(fā)表于 11-03 06:20

    如何pads2007轉(zhuǎn)換成cadence文件

    pads2007轉(zhuǎn)cadence:如何pads2007轉(zhuǎn)換成cadence文件
    發(fā)表于 09-14 09:55 ?0次下載
    如何<b class='flag-5'>將</b>pads2007<b class='flag-5'>轉(zhuǎn)換成</b>cadence文件

    pdf轉(zhuǎn)換成word轉(zhuǎn)換器下載

    此壓縮文件里面包含二款轉(zhuǎn)換工具:pdf轉(zhuǎn)換成word轉(zhuǎn)換器與word轉(zhuǎn)換成pdf轉(zhuǎn)換器。用戶可以選擇,
    發(fā)表于 09-18 09:17 ?110次下載
    pdf<b class='flag-5'>轉(zhuǎn)換成</b>word<b class='flag-5'>轉(zhuǎn)換</b>器下載

    利用物聯(lián)網(wǎng)工廠數(shù)據(jù)轉(zhuǎn)換成價值

    英特爾打造核心技術(shù)利用物聯(lián)網(wǎng)工廠數(shù)據(jù)轉(zhuǎn)換成價值
    發(fā)表于 12-28 18:00 ?0次下載

    如何RMS噪聲轉(zhuǎn)換成峰峰值噪聲

    ADI公司的Matt Duff就如何RMS噪聲轉(zhuǎn)換成峰峰值噪聲進行說明。
    的頭像 發(fā)表于 06-12 06:20 ?8781次閱讀

    Allegro設計轉(zhuǎn)換成POWER PCB的方法的教程免費下載

    本文檔的主要內(nèi)容詳細介紹的是Allegro 設計轉(zhuǎn)換成POWER PCB 的方法的教程免費下載。
    發(fā)表于 05-12 08:00 ?0次下載
    <b class='flag-5'>將</b>Allegro設計<b class='flag-5'>轉(zhuǎn)換成</b>POWER PCB的方法的教程免費下載
    主站蜘蛛池模板: 最美白嫩的极品美女ASSPICS| 丰满少妇67194视频| 亚洲高清国产拍精品5g| 午夜国产羞羞视频免费网站| 香蕉尹人综合精品| 亚洲成人免费观看| 一本一本之道高清在线观看| 91麻豆精品| xxx日本hd| 国产欧洲野花A级| 九九热这里有精品| 免费撕开胸罩吮胸视频| 日日碰狠狠添天天爽| 性刺激欧美三级在线现看中文| 亚洲乱码一区二区三区香蕉| 曰本女人牲交视频免费| YELLOW日本动漫高清免费| 国产精品第八页| 久久久无码AV精品亚洲A片软件| 女人的选择hd| 乡土女性网动态图解| 在线亚洲黄色| 成人天堂资源WWW在线| 国产原创剧情麻豆在线| 蜜桃麻豆WWW久久囤产精品免费 | 99成人在线视频| 国产爱豆剧果冻传媒在线| 护士们的母狗| 你的欲梦裸身在线播放| 无限资源在线观看高清| 中文字幕不卡在线高清| 电影 qvod| 久久视频在线视频观看天天看视频 | 最新在线黄色网址| 抽插内射高潮呻吟V杜V| 极品网红液液酱粉嫩福利照子凌酱 | 99在线免费| 国产毛片AV久久久久精品| 免费果冻传媒2021视频| 亚洲aaaa级特黄毛片| 99爱免费视频|