التزامن وتعدد الخيوط في Swift: المستوى المتقدم

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

التزامن وتعدد الخيوط في Swift: المستوى المتقدم

\n\n

تتطلب التطبيقات الحديثة لنظامي iOS وmacOS أداءً عاليًا واستجابة سريعة للواجهة. يتجاوز العمل المتقدم مع التزامن في Swift بكثير مجرد استخدام Grand Central Dispatch (GCD). في هذه المقالة، سنستعرض الأدوات الرئيسية في Swift 5.5+ لإدارة المهام غير المتزامنة: async/await، Actors، TaskGroup وبروتوكول Sendable. ستتعلم كيفية تجنب سباقات البيانات، وهيكلة الكود متعدد الخيوط بشكل صحيح، وتحسين الأداء.

\n\n

1. أساسيات async/await والتزامن المنظم (Structured Concurrency)

\n\n

الكلمات المفتاحية async و await هي أساس التزامن الحديث في Swift. فهي تسمح بكتابة كود غير متزامن يبدو وكأنه متزامن، مما يبسط القراءة والتصحيح بشكل كبير.

\n\n

إعلان دالة غير متزامنة:

\n
func fetchUserData() async throws -> User {\n    let url = URL(string: "https://api.example.com/user")!\n    let (data, _) = try await URLSession.shared.data(from: url)\n    let decoder = JSONDecoder()\n    return try decoder.decode(User.self, from: data)\n}
\n\n

استدعاء دالة غير متزامنة مع معالجة الأخطاء:

\n
Task {\n    do {\n        let user = try await fetchUserData()\n        print("User name: \\(user.name)")\n    } catch {\n        print("Failed to fetch user: \\(error)")\n    }\n}
\n\n

نقاط مهمة:

\n
    \n
  • التزامن المنظم (Structured Concurrency): كل مهمة غير متزامنة لها عمر محدد بوضوح، محدود بنطاق رؤية المهمة الأصلية Task.
  • \n
  • إلغاء المهام: إلغاء تلقائي للمهام الفرعية عند إلغاء المهمة الأصلية Task.
  • \n
  • الأولويات: استخدم Task(priority: .userInitiated) للمهام المهمة للمستخدم.
  • \n
\n\n

2. Actors: الحماية من سباقات البيانات

\n\n

قبل Swift 5.5، كان المطورون غالبًا ما يستخدمون قوائم انتظار GCD المتسلسلة لحماية الحالة المشتركة. توفر Actors عزلًا مدمجًا: الوصول إلى حالة الـ actor ممكن فقط من خلال await، مما يضمن سلامة الخيوط على مستوى المترجم.

\n\n

مثال على Actor لحساب بنكي:

\n
actor BankAccount {\n    private var balance: Double = 0.0\n\n    func deposit(amount: Double) {\n        balance += amount\n    }\n\n    func withdraw(amount: Double) throws {\n        guard balance >= amount else {\n            throw BankError.insufficientFunds\n        }\n        balance -= amount\n    }\n\n    func getBalance() -> Double {\n        return balance\n    }\n}\n\n// الاستخدام\nlet account = BankAccount()\nTask {\n    await account.deposit(amount: 100.0)\n    let currentBalance = await account.getBalance()\n    print("Balance: \\(currentBalance)")\n}
\n\n

مزايا Actors:

\n
    \n
  • فحص المترجم: محاولة الوصول إلى خاصية الـ actor بدون await ستؤدي إلى خطأ في الترجمة.
  • \n
  • إعادة الدخول (Reentrancy): يمكن للـ actor تعليق تنفيذ الطريقة الحالية (مثلاً عند استخدام await داخل الـ actor) ومعالجة استدعاء آخر، مما يمنع حالات الجمود (deadlocks).
  • \n
  • الأداء: تستخدم Actors آليات مزامنة محسّنة، وغالبًا ما تكون أسرع من الأقفال اليدوية.
  • \n
\n\n

3. TaskGroup: المعالجة المتوازية للبيانات

\n\n

عند الحاجة لتنفيذ عدة عمليات غير متزامنة مستقلة وانتظار اكتمالها، فإن TaskGroup هي الأداة المثالية. فهي تدير تلقائيًا عدد المهام المتوازية وتجمع النتائج.

\n\n

مثال لتحميل عدة صور بالتوازي:

\n
func downloadImages(urls: [URL])                

المدونات

توصيات الكتب