มีอะไรใหม่ใน .NET Core 2 และ C# 7 : App ไม่ค้างตอนอ่านไฟล์ใหญ่

App ไม่ค้างตอนอ่านไฟล์ใหญ่
ในตัวอย่างนี้เราจะอ่านไฟล์ขนาดใหญ่จากฮาร์ดดิสก์
ซี่งปรกติ App จะค้างเหมือนหยุดการทำงานไปจนกว่าจะอ่านไฟล์เสร็จ
ซึ่งอาจทำให้ผู้ใช้คิดว่า App มีปัญหาในการทำงาน
หากเรานำเทคนิคการใช้คำสั่ง async และ wait จะช่วยให้ App ไม่ค้าง
ผู้ใช้ยังคงมีปฏิสัมพันธ์กับ App ต่อไปได้
เราจะลองเขียนโค้ดภาษา C# กับ .NET Core 2.0 เพื่อทดสอบการทำงานของคำสั่ง async และ await
โดย 2 คำสั่งนี้ช่วยให้เกิดการทำงานคู่ขนาน
วิธีใช้คำสั่ง async ทำได้โดยนำไปใส่ไว้หน้าส่วนนิยามMethodที่ต้องการ
Method ที่ว่านี้มีข้อจำกัดที่จะมีค่าส่งกลับได้ 3 แบบ คือ void, Task และ Task<TResult> เท่านั้น
ดังนั้นโดยทั่วไปแล้วเรามักใช้ async Method ที่เป็น Method บริการอีเวนต์ เช่น
ซี่งปรกติ App จะค้างเหมือนหยุดการทำงานไปจนกว่าจะอ่านไฟล์เสร็จ
ซึ่งอาจทำให้ผู้ใช้คิดว่า App มีปัญหาในการทำงาน
หากเรานำเทคนิคการใช้คำสั่ง async และ wait จะช่วยให้ App ไม่ค้าง
ผู้ใช้ยังคงมีปฏิสัมพันธ์กับ App ต่อไปได้
เราจะลองเขียนโค้ดภาษา C# กับ .NET Core 2.0 เพื่อทดสอบการทำงานของคำสั่ง async และ await
โดย 2 คำสั่งนี้ช่วยให้เกิดการทำงานคู่ขนาน
วิธีใช้คำสั่ง async ทำได้โดยนำไปใส่ไว้หน้าส่วนนิยามMethodที่ต้องการ
Method ที่ว่านี้มีข้อจำกัดที่จะมีค่าส่งกลับได้ 3 แบบ คือ void, Task และ Task<TResult> เท่านั้น
ดังนั้นโดยทั่วไปแล้วเรามักใช้ async Method ที่เป็น Method บริการอีเวนต์ เช่น
- Method ที่ตอบสนองการกดปุ่ม
- Method รับข้อมูลจาก พอร์ทสื่อสาร และ
- Method ตอบสนอง timer
ในกรณีที่เป็น Method ที่มี ค่าส่งกลับแบบ Task เราสามารถใช้ตัวกระทำ await ภายใน Method นั้นได้ด้วย ตัวกระทำนี้มีหน้าที่หยุดการทำงานของ Thread ไว้จนกว่า Method จะจบ
ค่าส่งกลับแบบ Task อันที่จริงไม่ได้ส่งค่าอะไรกลับมา เราจึงไม่ต้อง และ ไม่สามารถรอรับสิ่งที่มันจะส่งกลับมาได้
ส่วน Method ที่มีค่าส่งกลับแบบ Task<TResult> เราสามารถกำหนดสิ่งที่จะส่งกลับได้
ยกตัวอย่างเช่น ถ้าเราต้องการส่งกลับค่าบูลีน เพื่อเป็นเครื่องแสดงความสำเร็จหรือล้มเหลว เราจะเขียนว่า Task<bool>
ค่าส่งกลับแบบ Task อันที่จริงไม่ได้ส่งค่าอะไรกลับมา เราจึงไม่ต้อง และ ไม่สามารถรอรับสิ่งที่มันจะส่งกลับมาได้
ส่วน Method ที่มีค่าส่งกลับแบบ Task<TResult> เราสามารถกำหนดสิ่งที่จะส่งกลับได้
ยกตัวอย่างเช่น ถ้าเราต้องการส่งกลับค่าบูลีน เพื่อเป็นเครื่องแสดงความสำเร็จหรือล้มเหลว เราจะเขียนว่า Task<bool>


ในโค้ดตัวอย่างแสดงวิธีใช้คำสั่ง async
เราสร้างโปรเจ็กต์แบบ Win Form แล้วใส่ปุ่ม Label และ Timer ให้ทำงานทุก ๆ 1 วินาที
ทุกครั้งที่ Timer รอครบ 1 วินาที method asyncTimer_Tick จะทำงานเพื่อแสดงจำนวนวินาทีในการทำงาน
เมื่อผู้ใช้กดปุ่มจะเกิดการคัดลอกไฟล์ขนาดใหญ่หลายไฟล์
บรรทัดที่ 19-24 กำหนดต้นทางและปลายทางของไฟล์ reset เริ่มการทำงานของ Timer แล้วสร้างรายชื่อของไฟล์ที่จะคัดลอก
บรรทัด 29-47 เริ่มกระบวนการคัดลอกไฟล์จากต้นทางไปปลายทาง
บรรทัด 38 คือคำสั่งที่ทำให้เกิดการคัดลอก ตัวเลข 81920 คือขนาด buffer
โปรดสังเกตว่าบรรทัดนี้มีตัวกระทำ await นำหน้า เพื่อให้เกิดการทำงานที่จะไม่ทำให้ Thread อื่น ๆ ค้าง
ระหว่างที่มันกำลังคัดลอกไฟล์ ผู้ใช้ยังคงสามารถโยกย้ายยืดหดหน้าฟอร์มได้และ Label ยังแสดงข้อความได้
การทำ Serialization กับ type ของเราเอง
การทำ Serialization หรือที่เรียกอีกอย่างหนึ่งว่าการทำ marshalling
คือ การแปลงภาวะของ object ให้กลายเป็น byte ข้อมูลในรูปแบบต่าง ๆ เช่น binary , XML และ JSON
เพื่อเก็บเป็น stream ไว้ในสื่อบันทึกหรือเพื่อส่งไปยังระบบอื่น ๆ ภายในเครือข่าย type ต่าง ๆ ของภาษา และ. Net มีคุณสมบัตินี้
และเราสามารถเขียนโค้ด C# กับ .NET Core เพื่อให้ typeของเราเองมีคุณสมบัตินี้ได้ด้วยเช่นกัน
Type ที่เรานิยามเองอาจเป็น class generic class , Enum และ Struct
ยกตัวอย่างเหตุการณ์ที่เราอาจจำเป็นต้องใช้ Serialization คือ
เราทำงานหนึ่งอยู่และต้องการพักงานนั้นไว้ชั่วคราว
โดยต้องการเก็บสถานะหรือภาวะของobjectทั้งหมดไว้ในฮาร์ดดิสก์
เพื่อที่จะสามารถนำกลับมาทำงานต่อภายหลัง ได้อย่างต่อเนื่องจากที่ทำค้างไว้
เราสร้างโปรเจ็กต์แบบ Win Form แล้วใส่ปุ่ม Label และ Timer ให้ทำงานทุก ๆ 1 วินาที
ทุกครั้งที่ Timer รอครบ 1 วินาที method asyncTimer_Tick จะทำงานเพื่อแสดงจำนวนวินาทีในการทำงาน
เมื่อผู้ใช้กดปุ่มจะเกิดการคัดลอกไฟล์ขนาดใหญ่หลายไฟล์
บรรทัดที่ 19-24 กำหนดต้นทางและปลายทางของไฟล์ reset เริ่มการทำงานของ Timer แล้วสร้างรายชื่อของไฟล์ที่จะคัดลอก
บรรทัด 29-47 เริ่มกระบวนการคัดลอกไฟล์จากต้นทางไปปลายทาง
บรรทัด 38 คือคำสั่งที่ทำให้เกิดการคัดลอก ตัวเลข 81920 คือขนาด buffer
โปรดสังเกตว่าบรรทัดนี้มีตัวกระทำ await นำหน้า เพื่อให้เกิดการทำงานที่จะไม่ทำให้ Thread อื่น ๆ ค้าง
ระหว่างที่มันกำลังคัดลอกไฟล์ ผู้ใช้ยังคงสามารถโยกย้ายยืดหดหน้าฟอร์มได้และ Label ยังแสดงข้อความได้
การทำ Serialization กับ type ของเราเอง
การทำ Serialization หรือที่เรียกอีกอย่างหนึ่งว่าการทำ marshalling
คือ การแปลงภาวะของ object ให้กลายเป็น byte ข้อมูลในรูปแบบต่าง ๆ เช่น binary , XML และ JSON
เพื่อเก็บเป็น stream ไว้ในสื่อบันทึกหรือเพื่อส่งไปยังระบบอื่น ๆ ภายในเครือข่าย type ต่าง ๆ ของภาษา และ. Net มีคุณสมบัตินี้
และเราสามารถเขียนโค้ด C# กับ .NET Core เพื่อให้ typeของเราเองมีคุณสมบัตินี้ได้ด้วยเช่นกัน
Type ที่เรานิยามเองอาจเป็น class generic class , Enum และ Struct
ยกตัวอย่างเหตุการณ์ที่เราอาจจำเป็นต้องใช้ Serialization คือ
เราทำงานหนึ่งอยู่และต้องการพักงานนั้นไว้ชั่วคราว
โดยต้องการเก็บสถานะหรือภาวะของobjectทั้งหมดไว้ในฮาร์ดดิสก์
เพื่อที่จะสามารถนำกลับมาทำงานต่อภายหลัง ได้อย่างต่อเนื่องจากที่ทำค้างไว้

โค้ดที่เห็นในโค้ดตัวอย่างแสดงวิธีทำ Serialization กับ Type ของเราเองเป็น Console App
บรรทัดที่ 4 นำเข้า Name Space System.Runtime.Serialization.Formatters.Binary
เพราะต้องการใช้เมธอด Serialize ในคลาส BinaryFormatter ของ Name Space นี้
บรรทัด 9-14 นิยามคลาส Cat ซึ่งในนั้นมีแค่ฟิลด์ Weight และ Age
โปรดสังเกตว่าคลาสนี้เป็น Abstract Class และ เราต้องการทำให้คลาสนี้มีความสามารถทำ Serialization ได้
เราจึงจำเป็นจะต้องใส่แอตทริบิวต์ชื่อ [Serializable] ไว้ที่บรรทัดก่อนหน้านิยามคลาส
บรรทัดที่ 4 นำเข้า Name Space System.Runtime.Serialization.Formatters.Binary
เพราะต้องการใช้เมธอด Serialize ในคลาส BinaryFormatter ของ Name Space นี้
บรรทัด 9-14 นิยามคลาส Cat ซึ่งในนั้นมีแค่ฟิลด์ Weight และ Age
โปรดสังเกตว่าคลาสนี้เป็น Abstract Class และ เราต้องการทำให้คลาสนี้มีความสามารถทำ Serialization ได้
เราจึงจำเป็นจะต้องใส่แอตทริบิวต์ชื่อ [Serializable] ไว้ที่บรรทัดก่อนหน้านิยามคลาส
บรรทัด 17-41 คือนิยามคลาส Tiger ซึ่งเป็นคลาสอนุพันธ์ (derived class) ของ Cat
และเราต้องการทำให้คลาสนี้มีความสามารถทำ Serialization ด้วยเช่นกัน
จึงต้องใส่แอตทริบิวต์ [Serializable] ไว้ก่อนหน้านิยามคลาส
ทั้งนี้เพราะความ Serialization จะไม่สืบสันดานจากเบสคลาสไปยังคลาสอนุพันธ์
คลาสอนุพันธ์จะต้องกำหนด Serialization ของมันเอง
และเราต้องการทำให้คลาสนี้มีความสามารถทำ Serialization ด้วยเช่นกัน
จึงต้องใส่แอตทริบิวต์ [Serializable] ไว้ก่อนหน้านิยามคลาส
ทั้งนี้เพราะความ Serialization จะไม่สืบสันดานจากเบสคลาสไปยังคลาสอนุพันธ์
คลาสอนุพันธ์จะต้องกำหนด Serialization ของมันเอง
บรรทัด 22-34 คือนิยาม Method SerializeTiger() ทำหน้าที่ให้คลาส Tiger สามารถทำ Serialization ได้
โปรดสังเกตว่า Method นี้มีค่าส่งกลับเป็น Stream ซึ่งเป็นตัวเก็บข้อมูลสถานะของ Object ที่ถูกทำ Serialization แล้ว
มันสร้าง Object จากคลาส Tiger แล้วกำหนดคุณสมบัติต่าง ๆ คือ Age, IsTamed, Trainer และ Weight ให้แก่ Object
จากนั้นบรรทัด 30 ใช้ Method BinaryFormatter() เพื่อแปลง Object tiger ให้กลายเป็น Serialization และอยู่ในรูปแบบสตรีมแล้วส่งกลับไปให้โค้ดที่เรียกมัน
โปรดสังเกตว่า Method นี้มีค่าส่งกลับเป็น Stream ซึ่งเป็นตัวเก็บข้อมูลสถานะของ Object ที่ถูกทำ Serialization แล้ว
มันสร้าง Object จากคลาส Tiger แล้วกำหนดคุณสมบัติต่าง ๆ คือ Age, IsTamed, Trainer และ Weight ให้แก่ Object
จากนั้นบรรทัด 30 ใช้ Method BinaryFormatter() เพื่อแปลง Object tiger ให้กลายเป็น Serialization และอยู่ในรูปแบบสตรีมแล้วส่งกลับไปให้โค้ดที่เรียกมัน
ส่วนการแปลงกลับจากสภาพ Serialization มาเป็น Object อย่างเดิมทำได้
โดยใช้โค้ดอย่างที่เห็นใน Method DeserializeTiger()
Method นี้รับพารามิเตอร์หนึ่งตัวเป็น Serialization ที่อยู่ในรูปแบบ stream
เราสามารถกำหนดตำแหน่งใน stream ที่จะเริ่มแปลงข้อมูลกลับได้โดยกำหนดที่พรอพเพอร์ตี Position ของ stream
กระบวนการแปลงเกิดขึ้นที่บรรทัด 39 โดยการเรียกMethod Deserializa() ของคลาส BinaryFormatter
บรรทัด 45-47 คือโค้ดที่ใช้เพื่อทดสอบการทำงานของคลาสนี้
อย่างไร ทดลองเขียนใช้คำสั่ง async และ wait ด้วยภาษา C# กับ .NET Core 2.0
เพื่อช่วยให้ App ไม่ค้าง ส่งผลดีทำให้ผู้ใช้ยังคงมีปฏิสัมพันธ์กับ App ต่อไปได้ดูนะครับ
โดยใช้โค้ดอย่างที่เห็นใน Method DeserializeTiger()
Method นี้รับพารามิเตอร์หนึ่งตัวเป็น Serialization ที่อยู่ในรูปแบบ stream
เราสามารถกำหนดตำแหน่งใน stream ที่จะเริ่มแปลงข้อมูลกลับได้โดยกำหนดที่พรอพเพอร์ตี Position ของ stream
กระบวนการแปลงเกิดขึ้นที่บรรทัด 39 โดยการเรียกMethod Deserializa() ของคลาส BinaryFormatter
บรรทัด 45-47 คือโค้ดที่ใช้เพื่อทดสอบการทำงานของคลาสนี้
อย่างไร ทดลองเขียนใช้คำสั่ง async และ wait ด้วยภาษา C# กับ .NET Core 2.0
เพื่อช่วยให้ App ไม่ค้าง ส่งผลดีทำให้ผู้ใช้ยังคงมีปฏิสัมพันธ์กับ App ต่อไปได้ดูนะครับ