ส่งเนื้อหาทั้งหมดของบัฟเฟอร์วงแหวนในการสมัครสมาชิกแล้วส่งข้อมูลใหม่

ฉันเป็นมือใหม่ในการ boost::asio

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

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

การใช้งานที่ไร้เดียงสาครั้งแรกที่ฉันคิดคือแยก asio::streambuf ออกจากกันสำหรับทุกการเชื่อมต่อและดันบัฟเฟอร์วงแหวนทั้งหมดเข้าไปในนั้นในการเชื่อมต่อและจากนั้นทุกข้อมูลใหม่ แต่ดูเหมือนว่าจะเป็นวิธีที่ไม่เหมาะมากในการทำทั้งสองอย่างในหน่วยความจำ และ cpu รอบเนื่องจากต้องคัดลอกข้อมูลสำหรับการเชื่อมต่อทุกครั้ง อาจหลายครั้งเพราะฉันไม่รู้ว่า boost::asio::send (หรือ linux tcp/ip stack) ทำการคัดลอกข้อมูลหรือไม่

เนื่องจากความคิดของฉันคือการไม่ใช้มัลติเธรดเลย ฉันกำลังคิดที่จะใช้คลาสที่ได้รับ asio::streambuf แบบกำหนดเองบางรูปแบบซึ่งแชร์บัฟเฟอร์จริงกับบัฟเฟอร์วงแหวน แต่เก็บสถานะแยกต่างหากของตัวชี้การอ่านโดยไม่จำเป็น ของล็อคใดๆ

ดูเหมือนว่าของฉันมันเป็นความต้องการที่ค่อนข้างผิดปกติเพราะฉันไม่พบเอกสาร/คำถามที่เกี่ยวข้องซึ่งเกี่ยวข้องกับหัวข้อที่คล้ายกันและเอกสารเสริมดูเหมือนค่อนข้างสั้นและหายากสำหรับฉัน (ดูเช่น: http://www.boost.org/doc/libs/1_57_0/doc/html/boost_asio/reference/basic_streambuf.html)

คงจะดีถ้ามีคนชี้แนะแนวคิดบางอย่างที่ฉันสามารถใช้เป็นจุดเริ่มต้นในการนำการออกแบบของฉันไปใช้ หรือชี้ให้ฉันไปที่การออกแบบทางเลือกอื่น หากเขา/เธอเห็นว่าของฉันไม่ดี นำไปปฏิบัติไม่ได้ และ/หรือปรับปรุงไม่ได้


person Patxitron    schedule 08.02.2015    source แหล่งที่มา
comment
การเพิ่มเอกสารประกอบดูเหมือนค่อนข้างหยาบคายและหายากสำหรับฉัน ฉันจะถือว่า หยาบคาย ไม่ได้หมายความว่าสิ่งที่คุณคิด คุณสามารถเชื่อมโยงไปยังเอกสารที่คุณไม่เข้าใจได้หรือไม่?   -  person sehe    schedule 08.02.2015
comment
ฉันได้เห็นการโหวตสองครั้ง ฉันได้แก้ไขคำถามเพื่อเพิ่มแท็ก linux แล้วฉันเห็น downvote หนึ่งอัน ฉันคิดว่าเป็นเพราะฉันทิ้งคำอธิบายสั้น ๆ สำหรับการแก้ไขไว้ดังนั้นฉันจึงแก้ไขอีกครั้งเพียงเพื่อปรับการแก้ไขครั้งก่อนและฉัน ' ได้เห็นการโหวตครั้งที่สอง ฉันไม่รู้ว่าฉันได้รับ downvote อัตโนมัติสำหรับการแก้ไขทุกครั้งหรือไม่ หรือมีคน downvote โดยไม่อธิบายเหตุผลของเขา/เธอ   -  person Patxitron    schedule 08.02.2015
comment
มันเป็นอย่างหลัง คำถามของคุณกว้างมากและไม่ได้แสดงถึงความพยายามใดๆ เป็นพิเศษ ฉันหมายความตามที่ฉันพูดจริงๆ คุณไม่แสดง /อะไร/ มันทำให้คุณเดือดร้อน คุณไม่สามารถคาดหวังให้เราสร้างตัวอย่างที่ใช้งานได้จริง แต่หากไม่มีโค้ดที่เป็นรูปธรรมที่คุณติดอยู่ คำถามนี้ดูเหมือนจะไม่เหมาะกับ SO (ฉันกำลังเขียนคำตอบอยู่นะคะ)   -  person sehe    schedule 08.02.2015
comment
คะแนนโหวตบางส่วนของคุณอาจมาจากการที่คุณไม่ได้โพสต์ข้อมูลโค้ดใดๆ เกี่ยวกับความพยายามของคุณเลย rude -› พื้นฐานอาจปรับปรุงการยอมรับคำถาม ;) นอกจากนี้หลายคนอาจไม่ชัดเจนว่าทำไมคุณไม่เพียงแค่อ่านจากไปป์ของคุณและให้บริการทั้งสองจุดปลายของคุณจาก 1 ฟังก์ชัน แต่อาจเป็นเพราะฉันไม่รู้เกี่ยวกับ boost:asio จริงๆ หากคุณต้องการบางสิ่งที่ปรับให้เหมาะสมที่สุด ให้ทำเอง (แทนที่จะใช้ไลบรารี่) ;)   -  person BitTickler    schedule 08.02.2015
comment
@sehe: ขออภัยหากฉันใช้คำหยาบคายในทางที่ผิด ฉันไม่ใช่คนที่พูดภาษาอังกฤษ และในภาษาสเปน rudo อาจเป็นคำที่นุ่มนวลกว่า ฉันอ้างถึง boost.org/doc /libs/1_57_0/doc/html/boost_asio/reference/ และฉันอยากจะบอกว่ามันดูเหมือนเริ่มต้นไม่เป็นมิตรกับฉันเพราะมันดูสั้นมากและมันอธิบายวิธีใช้ แต่ฉันไม่สามารถเข้าใจวิธีการได้มาจากมัน คลาสที่กำหนดเอง   -  person Patxitron    schedule 08.02.2015
comment
@Patxitron คุณสามารถอ้างถึงตัวอย่างมากมายได้ตลอดเวลา: boost .org/doc/libs/1_57_0/doc/html/boost_asio/examples.html   -  person sehe    schedule 08.02.2015
comment
@ user2225104 ฉันไม่สามารถโพสต์ข้อมูลโค้ดใด ๆ ได้เพราะคำถามของฉันเกี่ยวข้องกับการออกแบบมากกว่า คุณพูดถูก มันเป็นคำถามที่ค่อนข้างกว้าง แต่ฉันไม่สามารถหาพารามิเตอร์การค้นหาที่มีประโยชน์มาจำกัดให้แคบลงได้   -  person Patxitron    schedule 08.02.2015
comment
สิ่งที่ฉันยังไม่เห็นในคำถามของคุณคือเมื่อคุณละทิ้งข้อมูลที่คุณอ่านจากไปป์ของคุณในที่สุด เมื่อผู้บริโภครายแรกเชื่อมต่อหรือคุณต้องการเก็บข้อมูลของคุณตั้งแต่เริ่มต้นเพื่อให้ผู้บริโภครายใหม่ทั้งหมดมาถึง?   -  person BitTickler    schedule 08.02.2015
comment
@ user2225104 ความตั้งใจของฉันคือบัฟเฟอร์วงแหวนเก็บ N ไบต์สุดท้ายที่ได้รับจากไปป์ ไบต์ใหม่ที่ได้รับจะเขียนทับไบต์ที่เก่าที่สุด จากนั้นเมื่อผู้บริโภคเชื่อมต่อ N ไบต์ใหม่ล่าสุดจะถูกส่งไป จากนั้นทุกไบต์ใหม่ที่ได้รับทันทีที่ได้รับ ดังนั้นผู้บริโภคจึงไม่ละทิ้งข้อมูลจากบัฟเฟอร์วงแหวน และเนื้อหาทั้งหมด (ประวัติที่มีขนาดจำกัด) ก็มีให้สำหรับผู้บริโภครายใหม่   -  person Patxitron    schedule 08.02.2015
comment
หากคุณต้องการบางสิ่งที่ปรับให้เหมาะสม ทำมันเอง (แทนที่จะใช้ไลบรารี) ;) - @ user2225104 ฟังดูค่อนข้างกลับหัวสำหรับฉัน มีเนื้อหาเกี่ยวกับ กลุ่มอาการ NIH หรือการเลือกห้องสมุดที่ไม่ดี ฉันค่อนข้างมั่นใจว่าความสมดุลไม่ได้เป็นเช่นนั้นกับไลบรารี Boost มันอาจจะ /มากกว่าที่คุณต้องการ/ แต่แทบจะไม่ได้จำกัดเลยแม้แต่น้อย   -  person sehe    schedule 08.02.2015
comment
@sehe ทุกอย่างขึ้นอยู่กับว่าปัญหานั้นง่ายพอที่จะจัดการหรืออยู่นอกเหนือสิ่งที่เราสามารถทำได้ ฉันอยากจะใช้อัลกอริธึมทางคณิตศาสตร์ที่ได้รับการปรับปรุงจาก lib แต่สำหรับการเขียนคิว ฉันไม่อยาก (std::queue จะถือว่าไม่มีห้องสมุดที่นี่) หรือสำหรับการเปิดซ็อกเก็ตหรืออ่านจากท่อ ไม่ใช่ถ้าฉันต้องใช้เวลาในการเรียนรู้ห้องสมุดมากกว่าที่ฉันจะต้องเขียนเอง   -  person BitTickler    schedule 08.02.2015
comment
@ user2225104 ประเด็นก็คือมันต้องซับซ้อนมากเพื่อให้ไลบรารี่บูสต์ทั่วไปไม่สามารถติดตามได้อีกต่อไป แต่ฉันจะไม่โต้เถียงเรื่องรสชาติ เพราะนั่นคือไพ่ที่คุณดึงออกมาจริงๆ   -  person sehe    schedule 08.02.2015


คำตอบ (2)


คุณควรทำสิ่งที่คุณตั้งใจจะทำ

คุณไม่จำเป็นต้องมี streambuf เพื่อใช้กับ Boost Asio เลย: http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html

หากปัญหาคือจะหลีกเลี่ยงการให้ผู้ผลิต "รอ" จนกว่าผู้บริโภคทั้งหมด (อ่าน: การเชื่อมต่อ) จะส่งข้อมูลเสร็จสิ้น คุณสามารถใช้ ye olde tips ของการสลับบัฟเฟอร์เอาต์พุตได้ตลอดเวลา

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

ที่เกี่ยวข้องด้วย:

person sehe    schedule 08.02.2015
comment
เพิ่มลิงก์ไปยังพื้นหลังเพิ่มเติม (รวมถึงแนวคิดการออกแบบที่สมบูรณ์และลิงก์ไปยังการใช้งาน/การนำเสนอ) เกี่ยวกับการคัดลอกเป็นศูนย์โดยใช้ Boost Asio - person sehe; 08.02.2015

ดูเหมือนว่าประสิทธิภาพนั้นเป็นหัวข้อที่นี่ โดยไม่ขึ้นอยู่กับว่ามีการใช้ boost::asio หรือวิธีแก้ปัญหาที่ถักด้วยมือ ประสิทธิภาพ (ปริมาณงาน) อาจจะลดลงตามความเป็นจริงแล้ว (ตามที่ระบุไว้ในส่วนความคิดเห็นของ OP) ว่ามีการแลกเปลี่ยนไบต์เดียว (อ่านจาก ไปป์)
หลังจาก "เฟสต่อเนื่อง" เริ่มต้นเมื่อผู้บริโภคเชื่อมต่อ ไบต์เดียวจะไหลจากไปป์ไปยังซ็อกเก็ตผู้บริโภคที่เชื่อมต่อด้วยการดำเนินการอ่าน () และเขียน () ต่อไบต์ (หรือสองสามไบต์ หากแอปพลิเคชัน ไม่ได้ทำการโพลอย่างต่อเนื่อง)
เนื่องจาก (ความจริงที่ว่าราคาสำหรับการเรียกระบบ read() และ write() นั้นจ่ายสำหรับข้อมูลจำนวนเล็กน้อย) ฉันกล้าตั้งทฤษฎีว่าสิ่งใดก็ตามเกี่ยวกับหลายคิวหรือคิวเดียว ฯลฯ คือ อยู่ภายใต้เงาของ "ข้อบกพร่องด้านการออกแบบ" ขั้นพื้นฐานนั้นแล้ว ฉันใส่ "ข้อบกพร่องด้านการออกแบบ" ไว้ในเครื่องหมายคำพูด เนื่องจากไม่สามารถหลีกเลี่ยงได้เสมอไปที่จะต้องรับมือกับสถานการณ์ดังกล่าว

ดังนั้น หากไม่สามารถเพิ่มประสิทธิภาพปริมาณงานได้อยู่แล้ว ฉันขอแนะนำวิธีแก้ปัญหาที่ง่ายและตรงไปตรงมาที่สุดที่สามารถทำได้

คำสั่ง "no threads" ใน OP หมายถึงตัวอธิบายไฟล์ที่ไม่บล็อกสำหรับทั้งซ็อกเก็ตการยอมรับ ซ็อกเก็ตข้อมูลผู้บริโภค และไปป์ นี่จะเป็นแอปพลิเคชั่นโพลกิน CPU / คอร์อีก 100% หรือไม่ หากนี่ไม่ใช่ปัญหาพิเศษที่ได้รับการปรับให้เหมาะสมมากเกินไป ฉันไม่แนะนำให้ใช้ตัวอธิบายไฟล์ที่ไม่บล็อก นอกจากนี้ฉันจะไม่กังวลเกี่ยวกับสำเนาศูนย์หรือไม่

วิธีง่ายๆ อย่างหนึ่งในการใช้เธรดคือการทำให้ซ็อกเก็ตสำหรับผู้ใช้บริการไม่ปิดกั้น ขณะที่ไปป์อยู่ในโหมดปิดกั้น เธรดที่อ่านไปป์จะปั๊มข้อมูลลงในคิวและเรียกใช้ฟังก์ชันที่ให้บริการผู้บริโภคที่เชื่อมต่ออยู่ทั้งหมดในปัจจุบัน ซ็อกเก็ตการฟัง (อันที่เรียกยอมรับ ()) อยู่ในสถานะส่งสัญญาณ เมื่อการเชื่อมต่อไคลเอนต์ใหม่อยู่ระหว่างการพิจารณา ด้วยกลไกเช่น kqueue (bsd) หรือ epoll (linux เป็นต้น) หรือ WaitForMultipleObjects (windows) เธรดตัวอ่านไปป์สามารถตอบสนองสถานการณ์นั้นได้เช่นกัน

ในช่วงเวลาที่ไม่มีอะไรต้องทำ แอปพลิเคชันของคุณอยู่ในโหมดสลีป/บล็อก และเป็นมิตรกับสิ่งแวดล้อมของเรา :)

person BitTickler    schedule 08.02.2015
comment
ฉันคิดว่าฟังก์ชันอธิบายไฟล์ posix ของ boost::asio ทำสิ่ง epoll ให้ฉันโดยไม่ต้องใช้รอบ cpu ในการโพลที่ใช้งานอยู่ด้วยตัวเองเช่นเดียวกับใน boost.org/doc/libs/1_49_0/doc/html/boost_asio/example/chat/ อันที่จริง ฉันได้ทดลองใช้ฟีเจอร์นั้นแล้ว: github.com/patxitron/BattleyeRconToolLinux - person Patxitron; 09.02.2015
comment
คุณพูดถูก เมื่ออัปโหลดบัฟเฟอร์แล้ว ข้อมูลจะถูกส่งไม่ตามลำดับไบต์ทีละไบต์อย่างแน่นอน แต่จะส่งครั้งละไม่กี่ไบต์ (ส่วนใหญ่มักจะน้อยกว่า 100 ในเวลาเดียวกัน) ตอนนี้ฉันกำลังคิดที่จะส่งการอัปเดตเหล่านั้นโดยวนซ้ำซ็อกเก็ตที่ลงทะเบียนแล้ว ขอขอบคุณสำหรับความช่วยเหลือของคุณ. - person Patxitron; 09.02.2015