เหตุใดจึงมีความแตกต่างในเวลาดำเนินการของเสียงก้องและแมว?


15

การตอบคำถามนี้ทำให้ฉันถามคำถามอื่น:
ฉันคิดว่าสคริปต์ต่อไปนี้ทำสิ่งเดียวกันและอันที่สองควรเร็วกว่ามากเพราะการใช้ครั้งแรกcatที่ต้องการเปิดไฟล์ซ้ำไปซ้ำมา แต่อย่างที่สองเปิดไฟล์เท่านั้น เพียงครั้งเดียวและเพียงแค่ก้องตัวแปร:

(ดูหัวข้อการปรับปรุงสำหรับรหัสที่ถูกต้อง)

ครั้งแรก:

#!/bin/sh
for j in seq 10; do
  cat input
done >> output

ประการที่สอง:

#!/bin/sh
i=`cat input`
for j in seq 10; do
  echo $i
done >> output

ในขณะที่อินพุตประมาณ 50 เมกะไบต์

แต่เมื่อฉันลองครั้งที่สองมันก็ช้าเกินไปเพราะการสะท้อนตัวแปรiเป็นกระบวนการที่ยิ่งใหญ่ ฉันยังมีปัญหากับสคริปต์ที่สองเช่นขนาดของไฟล์ที่ส่งออกต่ำกว่าที่คาดไว้

ฉันยังตรวจสอบหน้า man ของechoและcatเปรียบเทียบ:

echo - แสดงบรรทัดข้อความ

cat - เชื่อมไฟล์และพิมพ์บนเอาต์พุตมาตรฐาน

แต่ฉันไม่ได้รับความแตกต่าง

ดังนั้น:

  • ทำไมแมวถึงเร็วขนาดนี้และเสียงก้องช้าในบทที่สอง?
  • หรือมีปัญหากับตัวแปรi? (เพราะในหน้า man ของ echoมันบอกว่ามันแสดง"a line of text"และดังนั้นฉันเดาว่ามันเหมาะสำหรับตัวแปรสั้นเท่านั้นไม่ใช่สำหรับตัวแปรที่ยาวมาก ๆ อย่างเช่นiอย่างไรก็ตามเป็นเพียงการเดา)
  • และเหตุผลที่ผมมีปัญหาเมื่อฉันใช้echo?

UPDATE

ฉันใช้seq 10แทน`seq 10`ไม่ถูกต้อง นี่คือรหัสที่แก้ไข:

ครั้งแรก:

#!/bin/sh
for j in `seq 10`; do
  cat input
done >> output

ประการที่สอง:

#!/bin/sh
i=`cat input`
for j in `seq 10`; do
  echo $i
done >> output

(ขอบคุณเป็นพิเศษสำหรับroaima )

อย่างไรก็ตามไม่ใช่ประเด็นของปัญหา แม้ว่าลูปจะเกิดขึ้นเพียงครั้งเดียว แต่ฉันก็มีปัญหาเดียวกัน: catทำงานได้เร็วกว่าechoมาก


1
แล้วมันเกี่ยวกับcat $(for i in $(seq 1 10); do echo "input"; done) >> outputอะไร? :)
netmonk

2
echoได้เร็วขึ้น สิ่งที่คุณพลาดคือการทำให้เชลล์ทำงานได้มากเกินไปโดยไม่ต้องพูดถึงตัวแปรเมื่อคุณใช้มัน
roaima

การอ้างอิงตัวแปรไม่ใช่ปัญหา ปัญหาคือตัวแปรฉันเอง (เช่นใช้เป็นขั้นตอนกลางระหว่างอินพุตและเอาต์พุต)
Aleksander

`echo $ i` - อย่าทำอย่างนี้ ใช้ printf และอ้างถึงข้อโต้แย้ง
PSkocik

1
@PSkocik สิ่งที่ผมพูดคือคุณต้องการไม่ได้printf '%s' "$i" echo $i@conglm อธิบายปัญหาบางอย่างของเสียงสะท้อนได้ดีในคำตอบของเขา สำหรับเหตุผลที่แม้แต่การอ้างถึงไม่เพียงพอในบางกรณีด้วย echo ดูunix.stackexchange.com/questions/65803/ …
PSkocik

คำตอบ:


24

มีหลายสิ่งที่ต้องพิจารณาที่นี่

i=`cat input`

อาจมีราคาแพงและมีการเปลี่ยนแปลงมากมายระหว่างเชลล์

นั่นเป็นคุณสมบัติที่เรียกว่าการทดแทนคำสั่ง แนวคิดคือการเก็บเอาต์พุตทั้งหมดของคำสั่งลบอักขระบรรทัดใหม่ต่อท้ายลงในiตัวแปรในหน่วยความจำ

ในการทำเช่นนั้นเชลล์แยกคำสั่งในเชลล์ย่อยและอ่านเอาต์พุตผ่านไพพ์หรือซ็อกเก็ตคู่ คุณเห็นการเปลี่ยนแปลงมากมายที่นี่ ในไฟล์ 50MiB นี่ผมสามารถมองเห็นเช่นทุบตีเป็นครั้งที่ 6 เป็นช้าเป็น ksh93 แต่เร็วขึ้นเล็กน้อยกว่า zsh yashและรวดเร็วเป็นสองเท่า

เหตุผลหลักสำหรับbashการช้าคือมันอ่านจากท่อ 128 ไบต์ในแต่ละครั้ง (ในขณะที่กระสุนอื่น ๆ อ่าน 4KiB หรือ 8KiB ในเวลา) และถูกลงโทษโดยการเรียกใช้ระบบ

zshจำเป็นต้องทำการโพสต์ - โพรเซสซิงเพื่อหลีกเลี่ยง NUL ไบต์ (เชลล์อื่นแบ่งเป็น NUL ไบต์) และyashทำการประมวลผลที่หนักยิ่งขึ้นโดยการแยกวิเคราะห์อักขระหลายไบต์

เชลล์ทั้งหมดจำเป็นต้องตัดอักขระบรรทัดใหม่ที่ต่อท้ายซึ่งอาจทำงานได้อย่างมีประสิทธิภาพมากหรือน้อย

บางคนอาจต้องการที่จะจัดการกับ NUL ไบต์อย่างสง่างามกว่าคนอื่น ๆ และตรวจสอบการปรากฏตัวของพวกเขา

จากนั้นเมื่อคุณมีตัวแปรขนาดใหญ่ในหน่วยความจำการจัดการใด ๆ ที่เกี่ยวข้องกับการจัดสรรหน่วยความจำเพิ่มเติมและการจัดการข้อมูลข้าม

ที่นี่คุณผ่าน (กำลังตั้งใจที่จะผ่าน) echoเนื้อหาของตัวแปรไป

โชคดีที่echoมีอยู่แล้วในเชลล์ของคุณมิฉะนั้นการประมวลผลอาจล้มเหลวด้วยรายการข้อผิดพลาดที่ยาวเกินไป แม้กระนั้นการสร้างอาร์เรย์รายการอาร์กิวเมนต์อาจเกี่ยวข้องกับการคัดลอกเนื้อหาของตัวแปร

ปัญหาหลักอื่น ๆ ในแนวทางการทดแทนคำสั่งของคุณคือคุณกำลังเรียกใช้ตัวดำเนินการแยก + glob (โดยลืมอ้างถึงตัวแปร)

สำหรับสิ่งนั้นเชลล์จำเป็นต้องใช้สตริงเป็นสตริงของอักขระ (แม้ว่าเชลล์บางตัวจะทำไม่ได้และเป็นบั๊กกี้ในเรื่องนั้น) ดังนั้นในโลแคล UTF-8 นั่นหมายถึงการแยกลำดับ UTF-8 (ถ้าไม่ได้ทำไปแล้วyash) ค้นหา$IFSอักขระในสตริง หาก$IFSมีช่องว่างแท็บหรือขึ้นบรรทัดใหม่ (ซึ่งเป็นกรณีโดยค่าเริ่มต้น) อัลกอริทึมจะซับซ้อนและมีราคาแพงยิ่งขึ้น จากนั้นคำที่เกิดจากการแยกจะต้องได้รับการจัดสรรและคัดลอก

ส่วน glob จะมีราคาแพงกว่า ถ้าใด ๆ ของคำเหล่านั้นประกอบด้วยอักขระ glob ( *, ?, [) แล้วเปลือกจะมีการอ่านเนื้อหาของไดเรกทอรีบางและทำบางจับคู่รูปแบบที่มีราคาแพง ( bashของการดำเนินงานเช่นเป็นฉาวโฉ่ที่เลวร้ายมากที่นั้น)

หากอินพุตมีบางสิ่งบางอย่างเช่น/*/*/*/../../../*/*/*/../../../*/*/*นั้นจะมีราคาแพงมากเพราะหมายถึงการระบุไดเรกทอรีหลายพันรายการและสามารถขยายไปหลายร้อย MiB

จากนั้นechoโดยทั่วไปจะทำการประมวลผลพิเศษบางอย่าง การใช้งานบางอย่างจะขยาย\xลำดับในอาร์กิวเมนต์ที่ได้รับซึ่งหมายถึงการแยกวิเคราะห์เนื้อหาและอาจเป็นการจัดสรรและคัดลอกข้อมูลอีกครั้ง

ในอีกทางหนึ่งตกลงในเชลล์ส่วนใหญ่catไม่ได้มีในตัวดังนั้นจึงหมายถึงการฟอร์กกระบวนการและดำเนินการ (เพื่อโหลดรหัสและไลบรารี) แต่หลังจากการเรียกใช้ครั้งแรกรหัสนั้นและเนื้อหาของไฟล์อินพุต จะถูกแคชในหน่วยความจำ ในทางกลับกันจะไม่มีคนกลาง catจะอ่านจำนวนมากในแต่ละครั้งและเขียนทันทีโดยไม่ต้องดำเนินการและไม่จำเป็นต้องจัดสรรหน่วยความจำจำนวนมากเพียงบัฟเฟอร์เดียวที่มันนำมาใช้ใหม่

นอกจากนี้ยังหมายความว่ามันมีความน่าเชื่อถือมากขึ้นเพราะไม่สำลักกับไบต์ NUL และไม่ตัดอักขระขึ้นบรรทัดใหม่ (และไม่แบ่ง + glob แม้ว่าคุณสามารถหลีกเลี่ยงปัญหานี้ได้ด้วยการอ้างอิงตัวแปรและไม่ ขยายลำดับ escape แม้ว่าคุณสามารถหลีกเลี่ยงได้โดยใช้printfแทนecho)

ถ้าคุณต้องการที่จะเพิ่มประสิทธิภาพของมันต่อไปแทนการกล่าวอ้างcatหลายครั้งเพียงแค่ผ่านinputหลาย ๆ catครั้งเพื่อ

yes input | head -n 100 | xargs cat

จะเรียกใช้ 3 คำสั่งแทน 100

เพื่อให้รุ่นตัวแปรเชื่อถือได้มากขึ้นคุณจะต้องใช้zsh(เชลล์อื่นไม่สามารถรับมือกับ NUL ไบต์) และทำมัน:

zmodload zsh/mapfile
var=$mapfile[input]
repeat 10 print -rn -- "$var"

หากคุณรู้ว่าอินพุตไม่มีไบต์ NUL แสดงว่าคุณสามารถทำ POSIXly ได้อย่างน่าเชื่อถือ (แม้ว่ามันอาจจะไม่ทำงานในที่ที่printfไม่มีบิวด์) ด้วย:

i=$(cat input && echo .) || exit # add an extra .\n to avoid trimming newlines
i=${i%.} # remove that trailing dot (the \n was removed by cmdsubst)
n=10
while [ "$n" -gt 10 ]; do
  printf %s "$i"
  n=$((n - 1))
done

แต่นั่นจะไม่มีประสิทธิภาพมากกว่าการใช้catลูป (เว้นแต่ว่าอินพุตจะเล็กมาก)


เป็นเรื่องที่ควรกล่าวถึงในกรณีที่มีการโต้แย้งยาวคุณจะได้รับหน่วยความจำไม่เพียงพอ ตัวอย่าง/bin/echo $(perl -e 'print "A"x999999')
cuonglm

คุณเข้าใจผิดกับข้อสันนิษฐานที่ว่าขนาดการอ่านมีอิทธิพลอย่างมีนัยสำคัญดังนั้นให้อ่านคำตอบของฉันเพื่อทำความเข้าใจเหตุผลที่แท้จริง
schily

@ schily ทำ 409600 อ่าน 128 ไบต์ใช้เวลามากขึ้น (เวลาระบบ) กว่า 800 อ่าน 64k เปรียบเทียบกับdd bs=128 < input > /dev/null dd bs=64 < input > /dev/nullจาก 0.6s ที่ใช้ในการทุบตีเพื่ออ่านไฟล์นั้น 0.4 ใช้ในการreadเรียกระบบเหล่านั้นในการทดสอบของฉันในขณะที่ shell อื่น ๆ ใช้เวลาน้อยลง
Stéphane Chazelas

ดูเหมือนคุณจะไม่ได้ทำการวิเคราะห์ประสิทธิภาพจริงๆ อิทธิพลของการเรียกการอ่าน (เมื่อเปรียบเทียบขนาดการอ่านที่แตกต่างกัน) คือ aprox 1% ของเวลาทั้งหมดในขณะที่ฟังก์ชั่นreadwc() และtrim()ในขุนศึกเชลล์ใช้เวลา 30% ของเวลาทั้งหมดและนี่คือการประเมินส่วนใหญ่มีแนวโน้มที่มี libc ไม่มีคำอธิบายประกอบสำหรับgprof mbtowc()
schily

ซึ่งจะ\xขยายตัว?
Mohammad

11

ปัญหาคือไม่ได้เกี่ยวกับcatและมันเป็นเรื่องของตัวแปรอ้างลืมecho$i

ในเชลล์สคริปต์ Bourne-like (ยกเว้นzsh) ปล่อยให้ตัวแปรไม่ระบุสาเหตุของglob+splitโอเปอเรเตอร์ในตัวแปร

$var

เป็นจริง:

glob(split($var))

ดังนั้นด้วยการวนซ้ำแต่ละครั้งเนื้อหาทั้งหมดของinput(ยกเว้นการขึ้นบรรทัดใหม่ต่อท้าย) จะถูกขยายแยกและกลม กระบวนการทั้งหมดต้องการเชลล์เพื่อจัดสรรหน่วยความจำโดยแยกสตริงซ้ำแล้วซ้ำอีก นั่นคือเหตุผลที่คุณได้รับประสิทธิภาพที่ไม่ดี

คุณสามารถอ้างอิงตัวแปรเพื่อป้องกันglob+splitแต่มันจะไม่ช่วยคุณมากนักเนื่องจากเมื่อเชลล์ยังต้องการสร้างอาร์กิวเมนต์สตริงขนาดใหญ่และสแกนเนื้อหาของมันecho(การแทนที่ builtin echoด้วยภายนอก/bin/echoจะทำให้รายการอาร์กิวเมนต์ยาวเกินไปหรือหน่วยความจำไม่เพียงพอ ขึ้นอยู่กับ$iขนาด) echoการใช้งานส่วนใหญ่ไม่ได้มาตรฐาน POSIX มันจะขยาย\xลำดับแบ็กสแลชในอาร์กิวเมนต์ที่ได้รับ

ด้วยcatเชลล์จะต้องวางไข่แต่ละกระบวนการวนซ้ำและcatจะทำสำเนา i / o ระบบยังสามารถแคชเนื้อหาไฟล์เพื่อทำให้กระบวนการ cat เร็วขึ้น


2
@roaima: คุณไม่ได้พูดถึงส่วน glob ซึ่งอาจเป็นเหตุผลใหญ่การถ่ายภาพสิ่งที่/*/*/*/*../../../../*/*/*/*/../../../../สามารถอยู่ในเนื้อหาของไฟล์ แค่อยากจะชี้ให้เห็นรายละเอียด
cuonglm

Gotcha ขอบคุณ แม้ไม่มีสิ่งนั้นเวลาก็เพิ่มเป็นสองเท่าเมื่อใช้ตัวแปรที่ไม่มี
เครื่องหมาย

1
time echo $( <xdditg106) >/dev/null real 0m0.125s user 0m0.085s sys 0m0.025s time echo "$( <xdditg106)" >/dev/null real 0m0.047s user 0m0.016s sys 0m0.022s
netmonk

ฉันไม่เข้าใจว่าทำไมการอ้างถึงไม่สามารถแก้ปัญหาได้ ฉันต้องการคำอธิบายเพิ่มเติม
Mohammad

1
@ mohammad.k: ตามที่ฉันเขียนไว้ในคำตอบของฉันตัวแปร quote ป้องกันglob+splitส่วนหนึ่งและจะเพิ่มความเร็วในขณะที่วนรอบ และฉันก็ตั้งข้อสังเกตว่ามันจะไม่ช่วยคุณมาก เนื่องจากเมื่อechoพฤติกรรมเชลล์ส่วนใหญ่ไม่เป็นไปตาม POSIX printf '%s' "$i"จะดีกว่า.
cuonglm

2

หากคุณโทรมา

i=`cat input`

สิ่งนี้จะช่วยให้กระบวนการเชลล์ของคุณเพิ่มขึ้น 50MB สูงสุด 200MB (ขึ้นอยู่กับการใช้งานอักขระที่มีความกว้างภายใน) นี่อาจทำให้เชลล์ของคุณช้า แต่นี่ไม่ใช่ปัญหาหลัก

ปัญหาหลักคือคำสั่งข้างต้นจำเป็นต้องอ่านไฟล์ทั้งหมดลงในหน่วยความจำเชลล์และecho $iจำเป็นต้องแยกฟิลด์ในเนื้อหาไฟล์$iนั้น ในการแยกฟิลด์ข้อความทั้งหมดจากไฟล์จะต้องถูกแปลงเป็นตัวกว้างและนี่คือที่ใช้เวลาส่วนใหญ่

ฉันทำแบบทดสอบช้าและได้ผลลัพธ์เหล่านี้:

  • เร็วที่สุดคือ ksh93
  • ถัดไปคือ Bourne Shell ของฉัน (2x ช้ากว่านั้น ksh93)
  • ถัดไปคือทุบตี (3x ช้ากว่า ksh93)
  • สุดท้ายคือ ksh88 (7x ช้ากว่า ksh93)

เหตุผลที่ ksh93 เร็วที่สุดดูเหมือนว่า ksh93 ไม่ได้ใช้mbtowc()จาก libc แต่เป็นการใช้งานของตัวเอง

BTW: สเตฟานเข้าใจผิดว่าขนาดการอ่านมีอิทธิพลบางอย่างฉันได้รวบรวมบอร์นเชลล์เพื่ออ่านใน 4096 ไบต์แทนที่จะเป็น 128 ไบต์และมีประสิทธิภาพเหมือนกันทั้งสองกรณี


i=`cat input`คำสั่งไม่ได้ทำแยกฟิลด์มันเป็นecho $iที่ไม่ เวลาที่ใช้ในการi=`cat input`จะเล็กน้อยเมื่อเทียบกับecho $iแต่ไม่เมื่อเทียบกับcat inputคนเดียวและในกรณีของbashความแตกต่างเป็นส่วนที่ดีที่สุดเนื่องจากbashการอ่านเล็ก ๆ การเปลี่ยนจาก 128 เป็น 4096 จะไม่มีผลต่อประสิทธิภาพการทำงานของecho $iแต่นั่นไม่ใช่จุดที่ฉันทำ
Stéphane Chazelas

นอกจากนี้โปรดทราบว่าประสิทธิภาพการทำงานecho $iจะแตกต่างกันไปอย่างมากขึ้นอยู่กับเนื้อหาของอินพุตและระบบไฟล์ (หากมี IFS หรือตัวอักษรกลม) ซึ่งเป็นเหตุผลที่ฉันไม่ได้ทำการเปรียบเทียบเชลล์ใด ๆ ในคำตอบของฉัน ตัวอย่างเช่นที่นี่ในผลลัพธ์ของyes | ghead -c50Mksh93 เป็นช้าที่สุดของทั้งหมด แต่บนyes | ghead -c50M | paste -sd: -มันเร็วที่สุด
Stéphane Chazelas

เมื่อพูดถึงเวลาทั้งหมดฉันกำลังพูดถึงการนำไปใช้ทั้งหมดและแน่นอนว่าการแยกฟิลด์เกิดขึ้นกับคำสั่ง echo และนี่คือที่ที่ใช้เวลาส่วนใหญ่ตลอดเวลา
schily

แน่นอนว่าคุณมีประสิทธิภาพที่ถูกต้องขึ้นอยู่กับเนื้อหาของ $ od
schily

1

ในทั้งสองกรณีวนซ้ำจะถูกเรียกใช้เพียงสองครั้ง (หนึ่งครั้งสำหรับคำseqและอีกครั้งสำหรับคำนั้น10)

ทั้งสองข้างจะรวมช่องว่างที่อยู่ติดกันและวางช่องว่างนำหน้า / ต่อท้ายเพื่อให้เอาต์พุตไม่จำเป็นต้องเป็นสำเนาสองชุดของอินพุต

เป็นครั้งแรก

#!/bin/sh
for j in $(seq 10); do
    cat input
done >> output

ที่สอง

#!/bin/sh
i="$(cat input)"
for j in $(seq 10); do
    echo "$i"
done >> output

สาเหตุหนึ่งที่ทำให้echoช้าลงอาจเป็นเพราะตัวแปรที่ไม่มีเครื่องหมายคำพูดของคุณถูกแยกที่ช่องว่างเป็นคำแยก สำหรับ 50MB นั้นจะทำงานได้มาก อ้างอิงตัวแปร!

ฉันขอแนะนำให้คุณแก้ไขข้อผิดพลาดเหล่านี้แล้วประเมินเวลาของคุณอีกครั้ง


ฉันได้ทดสอบสิ่งนี้ในพื้นที่แล้ว ฉันสร้างไฟล์ 50MB tar cf - | dd bs=1M count=50โดยใช้การส่งออกของ ฉันยังขยายลูปเพื่อให้ทำงานด้วยตัวคูณของ x100 เพื่อให้การกำหนดเวลาถูกปรับเป็นค่าที่เหมาะสม (ฉันได้เพิ่มลูปเพิ่มเติมรอบ ๆ โค้ดทั้งหมดของคุณ: for k in $(seq 100); do... done) นี่คือการกำหนดเวลา:

time ./1.sh

real    0m5.948s
user    0m0.012s
sys     0m0.064s

time ./2.sh

real    0m5.639s
user    0m4.060s
sys     0m0.224s

อย่างที่คุณเห็นไม่มีความแตกต่างจริง แต่ถ้าสิ่งใด ๆ ที่มีรุ่นechoทำงานเร็วกว่าเล็กน้อย ถ้าฉันลบเครื่องหมายคำพูดและรันเวอร์ชันที่ใช้งานไม่ได้ของคุณเวลาทวีคูณขึ้นสองเท่าแสดงให้เห็นว่าเชลล์ต้องทำงานมากกว่าที่ควรจะเป็น

time ./2original.sh

real    0m12.498s
user    0m8.645s
sys     0m2.732s

จริง ๆ แล้วการวนซ้ำจะทำงาน 10 ครั้งไม่ใช่สองครั้ง
fpmurphy

ฉันทำตามที่คุณพูด แต่ปัญหายังไม่ได้รับการแก้ไข catเร็วกว่าechoมาก สคริปต์แรกทำงานในเวลาเฉลี่ย 3 วินาที แต่สคริปต์ที่สองทำงานในเวลาเฉลี่ย 54 วินาที
Mohammad

@ fpmurphy1: ไม่ ฉันลองรหัสของฉัน การวนซ้ำทำงานเพียงสองครั้งไม่ใช่ 10 ครั้ง
Mohammad

@ mohammad.k เป็นครั้งที่สาม: หากคุณพูดถึงตัวแปรของคุณปัญหาจะหายไป
roaima

@roaima: คำสั่งtar cf - | dd bs=1M count=50ทำอะไร มันสร้างไฟล์ปกติที่มีตัวอักษรเหมือนกันข้างในหรือไม่ ถ้าเป็นเช่นนั้นในกรณีของฉันไฟล์อินพุตนั้นไม่สม่ำเสมอกับตัวละครและช่องว่างทุกประเภท และอีกครั้งฉันใช้timeตามที่คุณใช้และผลลัพธ์คือสิ่งที่ฉันพูด: 54 วินาทีเทียบกับ 3 วินาที
Mohammad

-1

read เร็วกว่ามาก cat

ฉันคิดว่าทุกคนสามารถทดสอบสิ่งนี้:

$ cd /sys/devices/system/cpu/cpu0/cpufreq
───────────────────────────────────────────────────────────────────────────────────────────
$ time for ((i=0; i<10000; i++ )); do read p < scaling_cur_freq ; done

real    0m0.232s
user    0m0.139s
sys     0m0.088s
───────────────────────────────────────────────────────────────────────────────────────────
$ time for ((i=0; i<10000; i++ )); do cat scaling_cur_freq > /dev/null ; done

real    0m9.372s
user    0m7.518s
sys     0m2.435s
───────────────────────────────────────────────────────────────────────────────────────────
$ type -a read
read is a shell builtin
───────────────────────────────────────────────────────────────────────────────────────────
$ type -a cat
cat is /bin/cat

catใช้เวลา 9.372 วินาที echoใช้เวลาไม่.232กี่วินาที

readเป็น40 ครั้งเร็ว

การทดสอบครั้งแรกของฉันเมื่อ$pถูกสะท้อนไปยังหน้าจอเปิดเผยreadเป็น 48 catครั้งเร็วกว่า


-2

echoจะหมายถึงการใส่สาย 1 บนหน้าจอ สิ่งที่คุณทำในตัวอย่างที่สองคือคุณใส่เนื้อหาของไฟล์ลงในตัวแปรแล้วพิมพ์ตัวแปรนั้น ในคนแรกคุณทันทีใส่เนื้อหาบนหน้าจอ

catเหมาะสำหรับการใช้งานนี้ echoไม่ใช่. การใส่ 50Mb ในตัวแปรสภาพแวดล้อมนั้นไม่ใช่ความคิดที่ดี


อยากรู้อยากเห็น ทำไมจะไม่echoเหมาะสำหรับการเขียนข้อความ
roaima

2
ไม่มีอะไรในมาตรฐาน POSIX ที่ระบุว่า echo นั้นหมายถึงการวางหนึ่งบรรทัดบนหน้าจอ
fpmurphy

-2

มันไม่เกี่ยวกับเสียงก้องเร็วขึ้นมันเกี่ยวกับสิ่งที่คุณทำ:

ในกรณีหนึ่งคุณกำลังอ่านจากอินพุตและเขียนไปยังเอาต์พุตโดยตรง กล่าวอีกนัยหนึ่งคืออะไรก็ตามที่อ่านจากอินพุตผ่าน cat ไปที่เอาต์พุตผ่าน stdout

input -> output

ในอีกกรณีหนึ่งคุณกำลังอ่านจากอินพุตไปยังตัวแปรในหน่วยความจำแล้วเขียนเนื้อหาของตัวแปรในเอาต์พุต

input -> variable
variable -> output

หลังจะช้ากว่ามากโดยเฉพาะถ้าอินพุท 50MB


ฉันคิดว่าคุณต้องพูดถึงว่าแมวต้องเปิดไฟล์เพิ่มเติมจากการคัดลอกจาก stdin และเขียนไปยัง stdout นี่คือความเป็นเลิศของบทที่สอง แต่บทแรกดีกว่าบทที่สองทั้งหมด
Mohammad

ไม่มีความเป็นเลิศในบทที่สอง cat ต้องเปิดไฟล์อินพุตในทั้งสองกรณี ในกรณีแรก stdout ของ cat ไปที่ไฟล์โดยตรง ในกรณีที่สอง stdout of cat ไปที่ตัวแปรก่อนจากนั้นคุณพิมพ์ตัวแปรลงในไฟล์เอาต์พุต
Aleksander

@ mohammad.k มีกึกก้องไม่มี "ความเป็นเลิศ" ในบทที่สอง
Wildcard
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.