การสร้างเธรด - Task.Factory.StartNew vs new Thread ()


102

ฉันเพิ่งเรียนรู้เกี่ยวกับ Threading และ Parallel libraries ใหม่ใน. Net 4

ในอดีตฉันจะสร้าง Thread ใหม่ในลักษณะนี้ (ดังตัวอย่าง):

DataInThread = new Thread(new ThreadStart(ThreadProcedure));
DataInThread.IsBackground = true;
DataInThread.Start();

ตอนนี้ฉันทำได้:

Task t = Task.Factory.StartNew(() =>
{
   ThreadProcedure();
});

อะไรคือความแตกต่างถ้ามี?

ขอบคุณ


1
คุณจะต้องหงุดหงิดเล็กน้อยเกี่ยวกับวิธีการทำงานของตัวกำหนดตารางเวลาเธรดพูล มันสามารถสร้างความแตกต่างได้มาก แต่ทั้งหมดขึ้นอยู่กับสิ่งที่คุณทำในเธรดจริงๆ
Hans Passant

คำตอบ:


79

มีความแตกต่างใหญ่ งานถูกกำหนดไว้บน ThreadPool และยังสามารถดำเนินการแบบซิงโครนัสได้หากเหมาะสม

หากคุณมีงานเบื้องหลังที่ทำงานเป็นเวลานานคุณควรระบุสิ่งนี้โดยใช้ตัวเลือกงานที่ถูกต้อง

คุณควรชอบ Task Parallel Library มากกว่าการจัดการเธรดอย่างชัดเจนเนื่องจากมีการปรับให้เหมาะสมมากกว่า นอกจากนี้คุณยังมีคุณสมบัติอื่น ๆ เช่นการต่อเนื่อง


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

10
มีตัวเลือก TaskCreationOptions.LongRunning ที่จะสร้างเธรดอื่นเสมอ แต่ประเด็นทั้งหมดคือทำไมคุณถึงต้องการเธรดอื่น? หากคุณแค่ต้องการทำบางอย่างควบคู่กันไป (Main ทำ sth. ในขณะที่ Task ทำงาน) ควรให้ไลบรารีที่ปรับให้เหมาะสมเป็นตัวเลือกว่าจะใช้ทรัพยากรระบบเช่นเธรดอย่างไรเพื่อทำสิ่งนี้อย่างมีประสิทธิภาพสูงสุด
sanosdole

3
บทความ msdn นี้อธิบายถึงวิธีการจัดกำหนดการงาน ครอบคลุมระยะยาวและ inlining (การดำเนินการแบบซิงโครนัส) msdn.microsoft.com/en-us/library/dd997402.aspx
sanosdole

2
@sming ประเด็นคือคุณต้องการประมวลผลพร้อมกัน (ไม่บล็อก UI) ไม่ใช่ว่าคุณต้องการเธรดใหม่ ThreadPool จะไม่ปิดกั้นเธรด UI แต่จัดการเธรดพื้นหลังได้อย่างมีประสิทธิภาพมากกว่าที่คุณสามารถทำได้ด้วยตนเองโดยการสร้างเธรด นั่นคือการเปลี่ยนแปลงในกระบวนการความคิดที่ TPL แนะนำ อย่าคิดหัวข้อคิดงานพร้อมกัน
sanosdole

4
@sming ขออภัยประโยคนั้นหยาบไปหน่อย การดำเนินงานแบบซิงโครนัสเรียกว่า inlining เมื่อกำหนดตารางงานบน threadpool (ตัวกำหนดตารางเวลาเริ่มต้น) จาก UI Thread จะไม่เกิดขึ้น จะเกิดขึ้นก็ต่อเมื่อตัวกำหนดตารางเวลาโดยรอบ ('TaskScheduler.Current') เหมือนกับตัวกำหนดตารางเวลาของงานที่คุณเรียก '.Wait ()' เนื่องจาก ".Wait ()" กำลังบล็อกอยู่จึงจะบล็อก UI อยู่ดี สั้น: อย่ารอสายและจะไม่ดำเนินการพร้อมกัน
sanosdole

74

งานนี้ช่วยให้คุณได้รับประโยชน์สูงสุดจากงาน API:

  • การเพิ่มความต่อเนื่อง ( Task.ContinueWith)
  • กำลังรอให้งานหลายอย่างเสร็จสมบูรณ์ (ทั้งหมดหรือทั้งหมด)
  • จับข้อผิดพลาดในงานและซักถามในภายหลัง
  • การบันทึกการยกเลิก (และอนุญาตให้คุณระบุการยกเลิกเพื่อเริ่มต้นด้วย)
  • อาจมีค่าส่งคืน
  • ใช้การรอใน C # 5
  • ควบคุมการจัดกำหนดการได้ดีขึ้น (ถ้าจะใช้งานได้ยาวนานให้พูดเช่นนั้นเมื่อคุณสร้างงานเพื่อให้ตัวกำหนดตารางเวลางานสามารถนำมาพิจารณาได้)

โปรดทราบว่าในทั้งสองกรณีคุณสามารถทำให้โค้ดของคุณง่ายขึ้นเล็กน้อยด้วยการแปลงกลุ่มวิธี:

DataInThread = new Thread(ThreadProcedure);
// Or...
Task t = Task.Factory.StartNew(ThreadProcedure);

8
+1. ฉันต้องการเพิ่มว่าThreadอยู่ในระดับต่ำมากเมื่อเทียบกับTask(ฉันมีบล็อกโพสต์ที่ลงรายละเอียด) ฉันให้เป็น "การใช้งานในโลกแห่งความจริง" ชนิดของการพูดคุยที่โรงแรมแกรนด์แรพิดส์ DevDay คำพูดนี้เรียกว่า "Thread is Dead" เนื่องจากไม่จำเป็นต้องใช้อีกต่อไปThread(เว้นแต่คุณจะใช้ a TaskScheduler)
Stephen Cleary

@StephenCleary ฉันคิดว่าคุณThreadคงตายแล้วเมื่อต้องใช้เป็นเธรดพื้นหลัง?
ebb

1
@ebb: ไม่ฉันมีตำแหน่งที่แข็งแกร่งกว่าที่อธิบายไว้ในความคิดเห็นแรกของฉัน ไม่มีอะไรที่Threadสามารถทำ (หรือBackgroundWorker) ที่ไม่สามารถทำได้มากขึ้นอย่างหรูหราด้วยและเหมาะสมTask TaskScheduler
Stephen Cleary

1
@StephenCleary คุณจะสร้างเธรดเฉพาะโดยไม่ใช้Threadอย่างไร
ebb

4
@ebb: "เธรดเฉพาะ" ไม่ชัดเจนสำหรับฉัน หากคุณต้องการTaskรันบนเธรดเฉพาะให้ใช้ที่เหมาะสมTaskScheduler- เช่นAsyncContextThread. อย่างไรก็ตามสิ่งนี้มักไม่จำเป็น SynchronizationContext, ThreadPoolและConcurrentExclusiveSchedulerPairschedulers มีเพียงพอสำหรับโปรแกรมส่วนใหญ่
Stephen Cleary

12

ในกรณีแรกคุณเพิ่งเริ่มเธรดใหม่ในขณะที่ในกรณีที่สองคุณกำลังเข้าสู่เธรดพูล

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

มีหลายวิธีในการเข้าสู่เธรดพูล:

  • ด้วยTPL (Task Parallel Library) เหมือนที่คุณทำ
  • โดยเรียกThreadPool.QueueUserWorkItem
  • โดยโทรหาBeginInvokeกับผู้รับมอบสิทธิ์
  • เมื่อคุณใช้BackgroundWorker

1

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

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

นี่คือความแตกต่างอย่างรวดเร็วระหว่างบล็อกรหัสที่กำหนด ต้องบอกว่ามีความแตกต่างโดยละเอียดเล็กน้อยซึ่งคุณสามารถ google หรือดูคำตอบอื่น ๆ จากผู้ร่วมให้ข้อมูลของฉัน

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