By Arnon Puitrakul - 20 กันยายน 2021
ก่อนหน้านี้เราอ่านเรื่องความแตกต่างระหว่าง is และเครื่องหมายเท่ากับในการเทียบค่ามา แล้วบังเอิญตอนเล่นบ้า ๆ อยู่ก็เอ๊ะ เจอพฤติกรรมแปลก ๆ ของ Python อยู่ ไปนั่งอ่านไปมา เขาเรียกว่า String Interning มันเป็นของที่ทำให้ Code ของเราเร็วขึ้นมาก ๆ โดยเฉพาะ ถ้าโปรแกรมของเรามีการเทียบ String จำนวนเยอะ ๆ มันเป็นยังไงไปลองดูกัน
ตอนที่เราเจอเรื่องนี้โดยบังเอิญ เราทำการเทียบ String 2 ตัวที่เหมือนกัน ลองดูใน Code ด้านล่าง
>>> a = "Me"
>>> b = "Me"
>>> a == b
True
>>> a is b
True
เราเทียบผ่านทั้งเครื่องหมายเท่ากับ และ is ไปด้วยกันเลย เรารู้อยู่แล้วว่า ทั้ง 2 String นี้มีค่าเท่ากัน การใช้เท่ากับ เป็นการเปรียบเทียบค่าของตัวแปรหรือ Object นั้น ๆ ทำให้ การที่เราใส่เครื่องหมายเท่ากับ แล้วมันออกมาเป็นจริง อันนี้ Make Sense แน่นอน แต่ ที่มันไม่ Make Sense มาก ๆ คือ เมื่อเราบอกว่า a is b ถ้าเราไปอ่านคำสั่ง is มา เราจะรู้ว่า มันไม่ได้เทียบค่าเลย แต่มันเทียบถึง Memory Address เลย
แปลว่า ถ้ามันได้ จริง ออกมา นั่นแปลว่า a และ b มันเป็นของชิ้นเดียวกันเลยเหรอ (ไม่ใช่แค่ค่านะ แต่มันถูกบันทึกอยู่ใน Memory Address เดียวกันเลย) ไหงงั้นละ เพราะเราไม่ได้บอกว่า b = a นิ แต่มันเท่ากันแบบ งง ๆ ลองดูอีกเคสแล้วจะ งง กว่าเดิมอีก
>>> c = "albert einstein"
>>> d = "albert einstein"
>>> c == d
True
>>> c is d
False
งั้นเราลองทำเหมือนเดิมเลยละกัน แต่กับ String ที่ยาวขึ้นอีก ลองใช้เท่ากับ อื้ม เหมือนกัน อันนี้ Make Sense แน่นอน แต่พอใช้ is เท่านั้นแหละ อ้าว อิหยังว้าาาา เมื่อกี้ยังเท่ากันอยู่เลย ทำไมเคสนี้มันไม่เท่าแล้วละ ไหงงั้น นัง Python แกทำให้ชั้นดูแย่ว์
พฤติกรรมที่เราลองให้ดูเมื่อครู่ เราเรียกมันว่า String Interning มันเป็นพฤติกรรมของ Python ที่มันจะเลือกเก็บแค่ Copy ของ String อันเดียวลงไปใน Memory เพื่อ ลดการใช้ Memory ลงได้ สมมุติว่า เรามี คำว่า Me สัก 200 ตัวแปร ถ้าเราต้องเก็บก็จะใช้ทั้งหมด 400 Bytes เฉพาะตัวข้อมูล ไม่นับส่วนการเก็บ Addressing ต่าง ๆ แต่ถ้าเราใช้ String Interning เราก็จะใช้แค่ 2 Byte เท่านั้น เพราะมันเก็บแค่ Copy เดียว ลดการใช้ Memory ไปได้มหาศาลเลย
อีกเหตุผลที่น่าสนใจมาก ๆ คือ การทำ String Comparation หรือการเทียบ String นั่นเอง ปกติแล้วเวลาเราจะเปรียบเทียบค่าของ String จริง ๆ เราจะต้อง Loop เข้าไปใน String ทั้ง 2 ตัวเลย แล้วถามว่า อักษรเดียวกันมั้ย แบบนี้ไปเรื่อย ๆ จนกว่าจะสุด String ใดสักตัว ถ้าเท่ากันหมด และ สุดของ String ทั้งสองพร้อม ๆ กัน ก็แปรว่า String นั้นแหละ มันค่าเท่ากัน ซึ่งการทำแบบนี้มันกินเวลามาก ๆ ตัว String Interning เลยบอกว่า งั้นถ้ามันเท่ากันจริง ๆ เราก็เก็บไว้ Copy เดียวเลย แปลว่า มันก็จะชี้ไปในที่ ๆ เดียวกันใน Memory ทำให้เวลาเราเทียบจริง ๆ เราก็เช็คจาก Address ได้เลย ทำให้มันเร็วขึ้นนั่นเอง
อ่านมาถึงขนาดนี้ เอ๊ะอะไรบ้างมั้ย การทำแบบนี้มันมีช่องโหว่อยู่ ถ้าเราบอกว่า มันเก็บ Copy เดียว นั่นแปลว่า ณ ตอนที่เราจะ Assign ค่าในตัวแปร มันจะต้องเข้าไปเช็คก่อนว่า ใน Variable มันมีอะไรบ้างที่เหมือนกัน มันไม่น้อยเลยนะ และใช้เวลาเยอะมาก ๆ โดยเฉพาะ ถ้า String เรายาวมาก ๆ การใช้ Intern ในเคสนี้อาจจะทำให้ชิบหายกันได้ ดังนั้นใน Python มันเลยจำกัดความยาวของ String ที่จะทำ String Interning โดยอัตโนมัติไว้เอง
import sys
>>> c = sys.intern("albert einstein")
>>> d = sys.intern("albert einstein")
>>> c == d
True
>>> c is d
True
แน่นอนว่า มนุษย์ที่หาทำอย่างเราก็อยากจะหาทำไปเรื่อย และ Python ก็ตอบสนองความหาทำได้เป็นอย่างดี เพราะมันมี Function รองรับเพื่อให้เราสามารถทำ String Interning ได้เลย ผ่าน Built-in Module sys ใน Function ที่ชื่อว่า intern() ตามชื่อของสิ่งที่เราต้องการเลย จะเห็นได้ว่า เราใช้ String ที่ยาว ตอนแรกถ้าเราใช้ is มันจะให้เป็น False มา แต่ตอนนี้เรา Force Intern เลย ทำให้เราเทียบ c is d มันเลยได้ True ออกมานั่นเอง
String Interning เป็นพฤติกรรมที่น่าสนใจมาก ๆ ใน Python ที่มันเลือกเก็บ String บางตัวไว้ Copy เดียว เพื่อลดขนาดของ Memory ที่ต้องใช้ และ ทำให้การ Compare หรือการเปรียบเทียบ String เร็วขึ้นได้อีก วันนี้เราก็พาไปดูใน 2 เคสคือ เคสที่ Python รับบทนาง Manage จัดการทำให้เราบน String ที่สั้นหน่อย และ เราก็ยังสามารถบังคับให้ Python ทำบน String ที่มีความยาวได้อยู่เช่นกัน
Obsidian เป็นโปรแกรมสำหรับการจด Note ที่เรียกว่า สารพัดประโยชน์มาก ๆ เราสามารถเอามาทำอะไรได้เยอะมาก ๆ หนึ่งในสิ่งที่เราเอามาทำคือ นำมาใช้เป็นระบบสำหรับการจัดการ Todo List ในแต่ละวันของเรา ทำอะไรบ้าง วันนี้เราจะมาเล่าให้อ่านกันว่า เราจัดการะบบอย่างไร...
อะ อะจ๊ะเอ๋ตัวเอง เป็นยังไงบ้างละ เมื่อหลายเดือนก่อน เราไปเล่าเรื่องกันขำ ๆ ว่า ๆ จริง ๆ แล้วพวก Loop ที่เราใช้เขียนโปรแกรมกันอยู่ มันไม่มีอยู่จริง สิ่งที่เราใช้งานกันมันพยายาม Abstract บางอย่างออกไป วันนี้เราจะมาถอดการทำงานของ Loop จริง ๆ กันว่า มันทำงานอย่างไรกันแน่ ผ่านภาษา Assembly...
นอกจากการทำให้ Application รันได้แล้ว อีกเรื่องที่สำคัญไม่แพ้กันคือการวางระบบ Monitoring ที่ดี วันนี้เราจะมาแนะนำวิธีการ Monitor การทำงานของ MySQL ผ่านการสร้าง Dashboard บน Grafana กัน...
จากตอนที่แล้ว เราเล่าในเรื่องของการ Harden Security ของ SSH Service ของเราด้วยการปรับการตั้งค่าบางอย่างเพื่อลด Attack Surface ที่อาจจะเกิดขึ้นได้ หากใครยังไม่ได้อ่านก็ย้อนกลับไปอ่านกันก่อนเด้อ วันนี้เรามาเล่าวิธีการที่มัน Advance มากขึ้น อย่างการใช้ fail2ban...