【速度測(cè)試】SketchUp圖元類型判斷的速度對(duì)比
上一篇文章[SU-2022-04]中提到,使用 typename 來(lái)判斷圖元類型,由于涉及字符串的對(duì)比,執(zhí)行效率較低,因而推薦使用 grep 或者 is_a? 方法。但是這兩種判斷方式在迭代圖元的過(guò)程中的執(zhí)行效率究竟差多少?為了解答這個(gè)問(wèn)題,本文做一個(gè)實(shí)驗(yàn)測(cè)試一下。
一、圖元類型判斷的方法
判斷一個(gè)圖元是否屬于某種類型有以下幾種方法,第一種方法直接判斷圖元類型,這一種方法可用的語(yǔ)法很多,至少包括以下幾種:
#令 ent 為一個(gè)圖元puts ent.typename == "Edge"puts ent.is_a?(Sketchup::Edge)puts ent.instance_of?(Sketchup::Edge)puts Sketchup::Edge === ent
以上均能夠判斷圖元 ent 是否是一個(gè)邊線類圖元,區(qū)別在于:第一種基于字符串的比較,等號(hào)左邊可能是 "Edge"、 "Face" 或者 "Group" 等字符串,通過(guò)和右邊的 "Edge" 對(duì)比確認(rèn) ent 是否為邊線類。余下三種都是基于ruby類的判斷,通過(guò)比較 ent 是否屬于 Sketchup::Edge 類來(lái)判斷。其中第三種方法中的 instance_of? 需要圖元必須是 Sketchup::Edge 也不能為其子類,但是對(duì)于 SketchUp 模型的情況而言,不存在上述情況,所以可以認(rèn)為是等價(jià)的。
第二種方法是判斷其是否擁有某些成員,例如邊線類都擁有長(zhǎng)度 length 成員,平面類都擁有面積 area 成員:
#令 ent 為一個(gè)圖元puts ent.respond_to?(:length)puts ent.methods.include?(:length)
這種方法的好處在于其清晰的目標(biāo)導(dǎo)向性,判斷圖元類型的很大一部分原因是為了避免類型不符的圖元拋出 NoMethodError 錯(cuò)誤,從而導(dǎo)致腳本意外終止。并且,對(duì)于某些特殊的情況可以很方便的表達(dá),例如需要同時(shí)選出組件、群組和圖片這三類圖元時(shí),由于這三種圖元對(duì)象都包括 :definition 方法,所以可以直接用以下方式判斷:
puts ent.respond_to?(:definition)第三種方法是直接不進(jìn)行判斷,將可能的拋出的異常用 begin rescue end 的方法來(lái)處理,這不是一個(gè)負(fù)責(zé)任的做法,但是某些時(shí)候可以用來(lái)跳過(guò)一些比較麻煩的篩選問(wèn)題。
begin# 不需要判斷圖元類型直接執(zhí)行rescue# 如果報(bào)錯(cuò)了不會(huì)拋出異常而是執(zhí)行這里的代碼,這里也可以是空的end
二、測(cè)試不同方法的運(yùn)行速度
這三種方法具體又可以分為不同的實(shí)現(xiàn)路徑,以下選取幾種方法,分別測(cè)試以下幾段代碼,測(cè)試其執(zhí)行速度:
#對(duì)比class的方法GC.starttz=Time.now().to_fedge_longer_than_10_meters=0Sketchup.active_model.entities.to_a.each{|ent|if ent.class==Sketchup::Edge thenif ent.length>10.m thenedge_longer_than_10_meters+=1endend}puts "長(zhǎng)度大于10米的邊線圖元數(shù)量:#{edge_longer_than_10_meters}"puts "總耗時(shí):#{Time.now().to_f-tz}秒"#使用is_a?的方法GC.starttz=Time.now().to_fedge_longer_than_10_meters=0Sketchup.active_model.entities.to_a.each{|ent|if ent.is_a?(Sketchup::Edge) thenif ent.length>10.m thenedge_longer_than_10_meters+=1endend}puts "長(zhǎng)度大于10米的邊線圖元數(shù)量:#{edge_longer_than_10_meters}"puts "總耗時(shí):#{Time.now().to_f-tz}秒"#對(duì)比typename的方法GC.starttz=Time.now().to_fedge_longer_than_10_meters=0Sketchup.active_model.entities.to_a.each{|ent|if ent.typename=="Edge" thenif ent.length>10.m thenedge_longer_than_10_meters+=1endend}puts "長(zhǎng)度大于10米的邊線圖元數(shù)量:#{edge_longer_than_10_meters}"puts "總耗時(shí):#{Time.now().to_f-tz}秒"#使用grep的方法GC.starttz=Time.now().to_fedge_longer_than_10_meters=0Sketchup.active_model.entities.grep(Sketchup::Edge).each{|ent|if ent.length>10.m thenedge_longer_than_10_meters+=1end}puts "長(zhǎng)度大于10米的邊線圖元數(shù)量:#{edge_longer_than_10_meters}"puts "總耗時(shí):#{Time.now().to_f-tz}秒"#判斷成員的方法GC.starttz=Time.now().to_fedge_longer_than_10_meters=0Sketchup.active_model.entities.to_a.each{|ent|if ent.respond_to?(:length) thenif ent.length>10.m thenedge_longer_than_10_meters+=1endend}puts "長(zhǎng)度大于10米的邊線圖元數(shù)量:#{edge_longer_than_10_meters}"puts "總耗時(shí):#{Time.now().to_f-tz}秒"#不使用to_a的is_a?方法GC.starttz=Time.now().to_fedge_longer_than_10_meters=0Sketchup.active_model.entities.each{|ent|if ent.is_a?(Sketchup::Edge) thenif ent.length>10.m thenedge_longer_than_10_meters+=1endend}puts "長(zhǎng)度大于10米的邊線圖元數(shù)量:#{edge_longer_than_10_meters}"puts "總耗時(shí):#{Time.now().to_f-tz}秒"#處理異常的方法GC.starttz=Time.now().to_fedge_longer_than_10_meters=0Sketchup.active_model.entities.to_a.each{|ent|beginif ent.length>10.m thenedge_longer_than_10_meters+=1endrescueend}puts "長(zhǎng)度大于10米的邊線圖元數(shù)量:#{edge_longer_than_10_meters}"puts "總耗時(shí):#{Time.now().to_f-tz}秒"#使用while的方法GC.starttz=Time.now().to_fedge_longer_than_10_meters=0index=0len=Sketchup.active_model.entities.lengthwhile index<len doent=Sketchup.active_model.entities[index]if ent.is_a?(Sketchup::Edge) thenif ent.length>10.m thenedge_longer_than_10_meters+=1endendindex+=1endputs "長(zhǎng)度大于10米的邊線圖元數(shù)量:#{edge_longer_than_10_meters}"puts "總耗時(shí):#{Time.now().to_f-tz}秒"
三、測(cè)試結(jié)果
通過(guò)運(yùn)行上一部分中的代碼,測(cè)試結(jié)果如下圖所示:

從測(cè)試結(jié)果來(lái)看,有以下幾條結(jié)論:
(1)使用ruby對(duì)象類型的判斷方法要比字符串判斷方法節(jié)約30%左右的時(shí)間。
(2)在不涉及修改圖元的情況下使用 while 語(yǔ)句非但沒(méi)有提速,反而速度較慢,因次沒(méi)有必要用它替代迭代器。
(3)判斷是否擁有成員的 respond_to? 方法速度也與判斷類型相近,因此對(duì)于上文所說(shuō)的群組組件的判斷,用此方法更為理想。
(4)有隔離影響功能的 to_a 方法會(huì)額外增加一小部分執(zhí)行時(shí)間,因此使用 grep 方法既可以獲得較高的執(zhí)行效率,同時(shí)還可以做到隔離影響,是相對(duì)而言最合理的方法。
(5)處理異常的 rescue 語(yǔ)句,速度低于字符串的比較,這是毫不意外的,實(shí)現(xiàn)具體功能時(shí)還是應(yīng)該盡量避免本身可控的不確定性。
(完)
本文編號(hào):SU-2022-05
