"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > لماذا تعتبر وظيفة "الإلحاق" غير آمنة للوصول المتزامن في Go؟

لماذا تعتبر وظيفة "الإلحاق" غير آمنة للوصول المتزامن في Go؟

تم النشر بتاريخ 2024-11-11
تصفح:649

Why is `append` function not thread-safe for concurrent access in Go?

وظيفة الإلحاق: ليست آمنة لمؤشر الترابط للوصول المتزامن

عند استخدام goroutines بشكل متزامن لإلحاق عناصر بشريحة داخل حلقة for، تحدث حالات شاذة في البيانات يمكن أن تنشأ. قد تظهر البيانات المفقودة أو الفارغة في الشريحة الناتجة، مما يشير إلى سباقات البيانات المحتملة.

يحدث هذا لأنه في Go، لا توجد قيمة آمنة بشكل طبيعي للقراءة والكتابة المتزامنة. الشرائح، التي يتم تمثيلها برؤوس الشرائح، ليست استثناءً. يعرض الكود المقدم سباقات البيانات بسبب الوصول المتزامن:

destSlice := make([]myClass, 0)

var wg sync.WaitGroup
for _, myObject := range sourceSlice {
    wg.Add(1)
    go func(closureMyObject myClass) {
        defer wg.Done()
        var tmpObj myClass
        tmpObj.AttributeName = closureMyObject.AttributeName
        destSlice = append(destSlice, tmpObj)
    }(myObject)
}
wg.Wait()

للتحقق من وجود سباقات البيانات، قم بتنفيذ الأمر التالي:

go run -race play.go

سوف ينبهك الإخراج إلى البيانات السباقات:

WARNING: DATA RACE
...

حل مشكلات التزامن

لحل هذه المشكلة، قم بحماية حق الوصول للكتابة إلى destSlice عن طريق استخدام المزامنة.Mutex:

var (
    mu        = &sync.Mutex{}
    destSlice = make([]myClass, 0)
)

var wg sync.WaitGroup
for _, myObject := range sourceSlice {
    wg.Add(1)
    go func(closureMyObject myClass) {
        defer wg.Done()
        var tmpObj myClass
        tmpObj.AttributeName = closureMyObject.AttributeName
        mu.Lock()
        destSlice = append(destSlice, tmpObj)
        mu.Unlock()
    }(myObject)
}
wg.Wait()

بدلاً من ذلك، فكر في استخدام قناة للتعامل بشكل غير متزامن مع الملحقات:

var (
    appendChan = make(chan myClass)
    destSlice  = make([]myClass, 0)
)

var wg sync.WaitGroup
for _, myObject := range sourceSlice {
    wg.Add(1)
    go func(closureMyObject myClass) {
        defer wg.Done()
        var tmpObj myClass
        tmpObj.AttributeName = closureMyObject.AttributeName
        appendChan 
أحدث البرنامج التعليمي أكثر>

تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.

Copyright© 2022 湘ICP备2022001581号-3