অবজেক্টিভ-সি এর "@ সিনক্রোনাইজড" এর সমান্তরাল কী?


231

আমি সুইফট বইটি সন্ধান করেছি, কিন্তু @ সিনক্রোনাইজডের সুইফট সংস্করণটি খুঁজে পাই না। আমি কীভাবে সুইফটে পারস্পরিক বর্জন করব?


1
আমি একটি প্রেরণ বাধা ব্যবহার করব। বাধা খুব সস্তা সিঙ্ক্রোনাইজেশন সরবরাহ করে। dispatch_barrier_async ()। ইত্যাদি
ফ্রেডেরিক সি। লি

@ ফ্রেডেরিকসি.লিলি, যদিও আপনার যদি একটি সিঙ্ক্রোনাইজ করার জন্য কোনও লেখার প্রয়োজন হয় যেমন র‍্যাপার তৈরি করার সময় removeFirst()?
স্কটিবিলেডস

উত্তর:


183

আপনি জিসিডি ব্যবহার করতে পারেন। এটি এর চেয়ে কিছুটা ভারবস @synchronized, তবে প্রতিস্থাপন হিসাবে কাজ করে:

let serialQueue = DispatchQueue(label: "com.test.mySerialQueue")
serialQueue.sync {
    // code
}

12
এটি দুর্দান্ত, তবে আপনার @ সিংক্রোনাইজডের সাথে পুনরায় প্রবেশের ক্ষমতা অভাব রয়েছে।
মাইকেল জলপ্রপাত

9
এই পদ্ধতির সাথে আপনার সতর্ক হওয়া দরকার। আপনার ব্লকটি অন্য কোনও থ্রেডে কার্যকর করা হতে পারে। এপিআই ডক্স বলছে: "একটি অপ্টিমাইজেশন হিসাবে, এই ফাংশনটি সম্ভব হলে বর্তমান থ্রেডে ব্লকটি আহ্বান করে।"
বায়ো

20
এই সম্পর্কে ম্যাট গ্যালাগারের দুর্দান্ত নিবন্ধ: cocoawithlove.com/blog/2016/06/02/threads-and-mutexes.html
wuf810

4
না, এর ফলে মাঝে মাঝে অচলাবস্থা দেখা দেয়।
টম ক্রাইনা

70
না, না এবং না। দুর্দান্ত চেষ্টা, কিন্তু অসম্পূর্ণভাবে ভাল কাজ করে। কেন? ম্যাট গ্যালাগারের প্রয়োজনীয় পাঠ (বিকল্পের তুলনায় সামগ্রিক তুলনা, সতর্কতা) এবং একটি দুর্দান্ত ইউটিলিটি কাঠামো: এখানে কোকোভিথ্লোভ.com / blog / 2016 / 06 / 02 / threads- এবং- mutexes.html @ wuf810 এই প্রথম (এইচটি) উল্লেখ করেছে, তবে এই নিবন্ধটি কতটা ভাল তা সংক্ষেপিত। সবার পড়া উচিত। (এটি প্রাথমিকভাবে দৃশ্যমান করার জন্য দয়া করে এটিকে নূন্যতম দ্বারা
উত্সাহিত করুন

181

আমি এটি নিজের জন্য সন্ধান করছিলাম এবং এই সিদ্ধান্তে পৌঁছেছি যে এটার জন্য দ্রুত কোনও অভ্যন্তরীণ নির্মাণ নেই।

আমি ম্যাট ব্রিজ এবং অন্যদের থেকে দেখেছি এমন কয়েকটি কোডের উপর ভিত্তি করে এই ছোট সহায়ক সাহায্যকারীর কাজটি করেছি।

func synced(_ lock: Any, closure: () -> ()) {
    objc_sync_enter(lock)
    closure()
    objc_sync_exit(lock)
}

ব্যবহার বেশ সোজা এগিয়ে

synced(self) {
    println("This is a synchronized closure")
}

এটির সাথে একটি সমস্যা খুঁজে পেয়েছি। লক আর্গুমেন্ট হিসাবে একটি অ্যারে পাস করার ফলে এই মুহুর্তে খুব অবসন্ন সংকলক ত্রুটি দেখা দেয়। অন্যথায় যদিও এটি পছন্দসই হিসাবে কাজ করে বলে মনে হচ্ছে।

Bitcast requires both operands to be pointer or neither
  %26 = bitcast i64 %25 to %objc_object*, !dbg !378
LLVM ERROR: Broken function found, compilation aborted!

নিস! দয়া করে এটির জন্য একটি বাগ ফাইল করুন যদি এটি এখনও 1.0
ম্যাটডি

14
এটি বেশ কার্যকর এবং @synchronizedব্লকের বাক্য গঠনটি সুন্দরভাবে সংরক্ষণ করে তবে লক্ষ্য করুন যে এটি @synchronizedঅবজেক্টিভ-সি-তে ব্লকের মতো বাস্তব বিল্টিন ব্লক স্টেটমেন্টের মতো নয় , কারণ returnএবং breakবিবৃতিগুলি আর পার্শ্ববর্তী ফাংশন / লুপের বাইরে চলে যাওয়ার পক্ষে কাজ করে না like এটা যদি এটি একটি সাধারণ বিবৃতি হয়।
newacct

3
ত্রুটি সম্ভবত অ্যারেগুলি রেফারেন্স হিসাবে মান হিসাবে পাস করার কারণে হতে পারে
james_alvarez

9
এটি সম্ভবত নতুন deferকীওয়ার্ডটি ব্যবহার করার জন্য দুর্দান্ত জায়গা হতে পারে তা ছোঁড়ার objc_sync_exitপরেও কল হয়ে যায় তা নিশ্চিত করে closure
devios1

3
@ t0rst লিঙ্ক-টু নিবন্ধের ভিত্তিতে এই উত্তরটিকে "ত্রুটিযুক্ত" কল করা বৈধ নয়। নিবন্ধটি বলেছে যে এই পদ্ধতিটি "আদর্শের তুলনায় কিছুটা ধীর" এবং "অ্যাপল প্ল্যাটফর্মগুলির মধ্যে সীমাবদ্ধ"। এটি দীর্ঘ শটে এটি "ত্রুটিযুক্ত" করে না।
রেনিপেট

150

আমি এখানে অনেক উত্তর পছন্দ এবং ব্যবহার করি, তাই আমি আপনার জন্য যে কোনটি ভাল কাজ করে তা চয়ন করব। এটি বলেছিল, যখন আমার উদ্দেশ্য-সি এর মতো কিছু দরকার তখন আমি যে পদ্ধতিটি পছন্দ করি তা সুইফট 2-এ প্রবর্তিত বিবৃতি @synchronizedব্যবহার করে defer

{ 
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }

    //
    // code of critical section goes here
    //

} // <-- lock released when this block is exited

এই পদ্ধতি সম্পর্কে চমৎকার জিনিস, যে আপনার সমালোচনামূলক ধারা পছন্দসই কোনো ফ্যাশন ধারণকারী ব্লক থেকে প্রস্থান করতে পারেন (যেমন, return, break, continue, throw), এবং "মুলতবি বিবৃতি মধ্যে বক্তব্য কোন ব্যাপার কিভাবে প্রোগ্রাম কন্ট্রোলের স্থানান্তর করা হয় মৃত্যুদন্ড কার্যকর করা হয়।" 1


আমি মনে করি এটি সম্ভবত এখানে সরবরাহ করা সবচেয়ে মার্জিত সমাধান। আপনার প্রতিক্রিয়ার জন্য ধন্যবাদ।
স্কট ডি

3
কী lock? কীভাবে শুরু করা lockহয়?
ভ্যান ডু ট্রান

6
lockযেকোন উদ্দেশ্য-সি বস্তু।
urউরোবুর

1
অসাধারণ! সুইফট 1 চালু হওয়ার সময় আমি কয়েকটি লক সহায়ক পদ্ধতি লিখেছিলাম এবং কিছুক্ষণের মধ্যে এগুলি পুনরায় দেখা হয়নি। মুলতুবি সম্পর্কে সম্পূর্ণরূপে ভুলে গেছি; এই পথেই!
র্যান্ডি

আমি এটি পছন্দ করি তবে এক্সকোড ৮-তে একটি সংকলক ত্রুটি পেয়েছি "বিবৃতিগুলির ব্রেসড ব্লকটি একটি অব্যবহৃত ক্লোজার" Ah আহ আমি পেয়েছি এটি কেবল ফাংশন ধনুর্বন্ধনী - আপনার "1" রেফারেন্স লিঙ্কটি খুঁজে পেতে খুব বেশি সময় - ধন্যবাদ!
ডানকান গ্রেনেওয়াল্ড

83

আপনি objc_sync_enter(obj: AnyObject?)এবং এর মধ্যে বিবৃতি স্যান্ডউইচ করতে পারেন objc_sync_exit(obj: AnyObject?)। @ সিংক্রোনাইজড কীওয়ার্ডটি কভারগুলির আওতায় সেই পদ্ধতিগুলি ব্যবহার করছে। অর্থাত

objc_sync_enter(self)
... synchronized code ...
objc_sync_exit(self)

3
এটি কি অ্যাপল দ্বারা একটি প্রাইভেট এপিআই ব্যবহার হিসাবে বিবেচিত হবে?
ড্রুक्स

2
না, objc_sync_enterএবং objc_sync_exitওবজেসি-সিঙ্ক.হ. এ সংজ্ঞায়িত পদ্ধতিগুলি এবং ওপেন সোর্স: ওপেনসোর্স.এপল
বিজেসি

যদি একাধিক থ্রেড একই সংস্থানটি অ্যাক্সেস করার চেষ্টা করে, দ্বিতীয়টি কী অপেক্ষা করে, পুনরায় চেষ্টা করে বা ক্র্যাশ করে?
TruMan1

@ বন্টোজেআর যা বলেছে তার সাথে যুক্ত করা, objc_sync_enter(…)এবং objc_sync_exit(…)আইওএস / ম্যাকোস / ইত্যাদি দ্বারা সরবরাহিত সর্বজনীন শিরোনাম। API গুলি (দেখে মনে হচ্ছে এগুলি ….sdkপথের ভিতরে রয়েছে usr/include/objc/objc-sync.h) । কোনও কিছু পাবলিক এপিআই বা না তা সন্ধান করার সহজ উপায়টি (এক্সকোডে) ফাংশনটির নাম টাইপ করা (যেমন objc_sync_enter(); সি ফাংশনগুলির জন্য আর্গুমেন্ট নির্দিষ্ট করার দরকার নেই) , তারপরে কমান্ড-ক্লিক করার চেষ্টা করুন। যদি এটি আপনাকে সেই API এর শিরোনাম ফাইলটি দেখায়, তবে আপনি ভাল (যেহেতু আপনি শিরোনামটি সর্বজনীন না হলে আপনি দেখতে সক্ষম হবেন না)
স্লিপ ডি থম্পসন

75

@synchronizedঅবজেক্টিভ-সি থেকে প্রাপ্ত নির্দেশিকার অ্যানালগটিতে সুইফটে একটি নির্বিচারে রিটার্ন টাইপ এবং দুর্দান্ত rethrowsআচরণ থাকতে পারে।

// Swift 3
func synchronized<T>(_ lock: AnyObject, _ body: () throws -> T) rethrows -> T {
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }
    return try body()
}

deferবিবৃতিটির ব্যবহার অস্থায়ী ভেরিয়েবলের পরিচয় না দিয়ে সরাসরি কোনও মান ফেরত দেয়।


@noescapeআরও অপটিমাইজেশনের অনুমতি দিতে সুইফট 2- এ ক্লোজারে অ্যাট্রিবিউট যুক্ত করুন :

// Swift 2
func synchronized<T>(lock: AnyObject, @noescape _ body: () throws -> T) rethrows -> T {
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }
    return try body()
}

জিএনউইউসিসি [১] (যেখানে আমি নির্বিচারে রিটার্নের ধরণটি পছন্দ করি) এবং টড কানিংহাম [2] (যেখানে আমি পছন্দ করি defer) এর উত্তরগুলির উপর ভিত্তি করে ।


এক্সকোড আমাকে বলছে যে @ ননোস্কেপ এখন ডিফল্ট এবং সুইফট ৩
অবমূল্যায়িত হয়েছে

এটা ঠিক, এই উত্তরের কোডটি সুইফট 2 এর জন্য এবং এতে সুইফট ৩-এর জন্য কিছু অভিযোজন প্রয়োজন I'll
ওয়েলডিভার

1
আপনি ব্যবহার ব্যাখ্যা করতে পারেন? সম্ভবত একটি উদাহরণ সহ .. অগ্রিম ধন্যবাদ! আমার ক্ষেত্রে আমার একটি সেট রয়েছে যা আমার সিঙ্ক্রোনাইজ করা দরকার, কারণ আমি এর বিষয়বস্তু একটি ডিসপ্যাচকিউতে চালিত করি।
সানচো

@ সানচো আমি এই পোস্টটি সংক্ষিপ্ত রাখতে পছন্দ করব আপনি সাধারণ একযোগে প্রোগ্রামিং গাইডলাইন সম্পর্কে জিজ্ঞাসা করছেন বলে মনে হচ্ছে, এটি একটি বিস্তৃত প্রশ্ন। এটি একটি পৃথক প্রশ্ন হিসাবে জিজ্ঞাসা করার চেষ্টা করুন!
ওয়েলডিভার

41

সুইফট 4

সুইফ্ট 4-এ আপনি জিসিডি প্রেরণ সারিগুলি লক সংস্থানগুলিতে ব্যবহার করতে পারেন।

class MyObject {
    private var internalState: Int = 0
    private let internalQueue: DispatchQueue = DispatchQueue(label:"LockingQueue") // Serial by default

    var state: Int {
        get {
            return internalQueue.sync { internalState }
        }

        set (newState) {
            internalQueue.sync { internalState = newState }
        }
    }
} 

এটি XCode8.1 এর সাথে কাজ করছে বলে মনে হচ্ছে না। .serialঅনুপলব্ধ বলে মনে হচ্ছে। তবে .concurrentপাওয়া যায়। : /
ট্র্যাভিস গ্রিগস

2
ডিফল্ট হ'ল .সিরিয়াল
ডানকান

2
নোট করুন যে এই ধরণটি বেশিরভাগ সাধারণ মাল্টি থ্রেড সমস্যার বিরুদ্ধে সঠিকভাবে রক্ষা করে না। উদাহরণস্বরূপ, আপনি যদি myObject.state = myObject.state + 1একই সাথে চালনা করেন তবে এটি মোট ক্রিয়াকলাপ গণনা করবে না বরং পরিবর্তে একটি অ-নিরপেক্ষবাদী মান অর্জন করবে। এই সমস্যাটি সমাধান করার জন্য, কলিং কোডটি সিরিয়াল কাতারে আবৃত করা উচিত যাতে পাঠানো এবং লেখার উভয়ই পরমাণুভাবে ঘটে। অবশ্যই ওবজ-সি এর @synchronisedএকই সমস্যা রয়েছে, সুতরাং সেই অর্থে আপনার বাস্তবায়নটি সঠিক।
বেরিক

1
হ্যাঁ, myObject.state += 1একটি পঠন এবং তারপরে একটি রাইটিং অপারেশনের সংমিশ্রণ। কিছু অন্যান্য থ্রেড এখনও মান নির্ধারণ / লিখতে অভ্যন্তরে আসতে পারে। অনুযায়ী objc.io/blog/2018/12/18/atomic-variables , এটি চালানোর জন্য সহজ হবে setপরিবর্তনশীল নিজেই অধীনে পরিবর্তে এবং একটি সিঙ্ক ব্লক / অবসান হবে।
সাইবারমিউউ

23

রিটার্নের কার্যকারিতা যুক্ত করতে আপনি এটি করতে পারেন:

func synchronize<T>(lockObj: AnyObject!, closure: ()->T) -> T
{
  objc_sync_enter(lockObj)
  var retVal: T = closure()
  objc_sync_exit(lockObj)
  return retVal
}

পরবর্তীকালে, আপনি এটি ব্যবহার করে কল করতে পারেন:

func importantMethod(...) -> Bool {
  return synchronize(self) {
    if(feelLikeReturningTrue) { return true }
    // do other things
    if(feelLikeReturningTrueNow) { return true }
    // more things
    return whatIFeelLike ? true : false
  }
}

23

ব্রায়ান ম্যাকলিমোর উত্তরটি ব্যবহার করে, আমি সুইট ২.০ ডিফার সক্ষমতার সাহায্যে সুরক্ষিত ম্যানর আটকানো অবজেক্টগুলিকে সমর্থন করার জন্য এটি বাড়িয়েছি।

func synchronized( lock:AnyObject, block:() throws -> Void ) rethrows
{
    objc_sync_enter(lock)
    defer {
        objc_sync_exit(lock)
    }

    try block()
}

আমার উত্তরে দেখানো হিসাবে rethrowsনিক্ষেপণ বন্ধ (ব্যবহারের প্রয়োজন নেই try) দিয়ে ব্যবহারকে সহজ করার জন্য ব্যবহার করা ভাল ।
ওয়েডাইভার

10

সুইফট 3

এই কোডটিতে পুনরায় প্রবেশের ক্ষমতা রয়েছে এবং এটি অ্যাসিঙ্ক্রোনাস ফাংশন কলগুলির সাথে কাজ করতে পারে। এই কোডে, কিছুAsyncFunc () বলা হওয়ার পরে, সিরিয়াল কাতারে অন্য একটি ফাংশন বন্ধ হওয়ার প্রক্রিয়া শুরু হবে তবে সিগন্যাল () বলা না হওয়া অবধি semaphore.wait () দ্বারা অবরুদ্ধ করা হবে। অভ্যন্তরীণ কিউ.সেনসি ব্যবহার করা উচিত নয় কারণ এটি ভুল না হলে এটি মূল থ্রেডটিকে ব্লক করে দেবে।

let internalQueue = DispatchQueue(label: "serialQueue")
let semaphore = DispatchSemaphore(value: 1)

internalQueue.async {

    self.semaphore.wait()

    // Critical section

    someAsyncFunc() {

        // Do some work here

        self.semaphore.signal()
    }
}

mistc_sync_enter / objc_sync_exit ত্রুটি পরিচালনা করা ছাড়া ভাল ধারণা নয়।


কী ত্রুটি পরিচালনা? সংকলক ছুড়ে ফেলে এমন কিছুকে অনুমতি দেবে না। অন্যদিকে, objc_sync_enter / প্রস্থান ব্যবহার না করে আপনি কিছু উল্লেখযোগ্য পারফরম্যান্স লাভ ছেড়ে দেন।
gnasher729

8

2018 ডাব্লুডাব্লুডিসির "ক্র্যাশগুলি এবং ক্র্যাশ লগগুলি বোঝার" সেশনে 414 তারা সিঙ্কের সাথে ডিসপ্যাচকিউগুলি ব্যবহার করে নিম্নলিখিত পদ্ধতিটি দেখায়।

সুইফ্ট 4 এ নিম্নলিখিতগুলির মতো কিছু হওয়া উচিত:

class ImageCache {
    private let queue = DispatchQueue(label: "sync queue")
    private var storage: [String: UIImage] = [:]
    public subscript(key: String) -> UIImage? {
        get {
          return queue.sync {
            return storage[key]
          }
        }
        set {
          queue.sync {
            storage[key] = newValue
          }
        }
    }
}

যাইহোক আপনি বাধা সহ সমবর্তী সারি ব্যবহার করে দ্রুত পাঠগুলিও তৈরি করতে পারেন। সিঙ্ক এবং অ্যাসিঙ্ক রিডগুলি একই সাথে সঞ্চালিত হয় এবং একটি নতুন মান লেখা পূর্ববর্তী ক্রিয়াকলাপ সমাপ্ত হওয়ার জন্য অপেক্ষা করে।

class ImageCache {
    private let queue = DispatchQueue(label: "with barriers", attributes: .concurrent)
    private var storage: [String: UIImage] = [:]

    func get(_ key: String) -> UIImage? {
        return queue.sync { [weak self] in
            guard let self = self else { return nil }
            return self.storage[key]
        }
    }

    func set(_ image: UIImage, for key: String) {
        queue.async(flags: .barrier) { [weak self] in
            guard let self = self else { return }
            self.storage[key] = image
        }
    }
}

আপনার সম্ভবত সিঙ্ক ব্যবহার করে পঠন এবং কাতারটি ধীর করার প্রয়োজন নেই। আপনি কেবল সিরিয়াল লেখার জন্য সিঙ্ক ব্যবহার করতে পারেন।
বশির_ক্যাড

6

সুইফট 4 এ এনএসলক ব্যবহার করুন :

let lock = NSLock()
lock.lock()
if isRunning == true {
        print("Service IS running ==> please wait")
        return
} else {
    print("Service not running")
}
isRunning = true
lock.unlock()

সতর্কতা এনএসলক শ্রেণিটির লকিং আচরণটি বাস্তবায়নের জন্য পসিক্স থ্রেড ব্যবহার করে। কোনও এনএসলক অবজেক্টে আনলক বার্তা প্রেরণ করার সময় আপনাকে অবশ্যই নিশ্চিত হওয়া উচিত যে বার্তাটি একই থ্রেড থেকে প্রেরণ করা হয়েছিল যা প্রাথমিক লক বার্তা প্রেরণ করেছে। কোনও আলাদা থ্রেড থেকে লক আনলক করা অনির্ধারিত আচরণের ফলস্বরূপ।



6

আধুনিক সুইফট 5 এ, রিটার্ন সক্ষমতার সাথে:

/**
Makes sure no other thread reenters the closure before the one running has not returned
*/
@discardableResult
public func synchronized<T>(_ lock: AnyObject, closure:() -> T) -> T {
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }

    return closure()
}

রিটার্ন মান সক্ষমতা সদ্ব্যবহার করতে এটি এটিকে ব্যবহার করুন:

let returnedValue = synchronized(self) { 
     // Your code here
     return yourCode()
}

বা অন্যথায় যে মত:

synchronized(self) { 
     // Your code here
    yourCode()
}

2
এটি সঠিক উত্তর এবং গ্রহণযোগ্য এবং উচ্চ উত্সাহিত কোনও নয় (যা নির্ভর করে GCD)। এটি মূলত বলে মনে হয় Noone ব্যবহারসমূহ বা কিভাবে ব্যবহার করতে বুঝতে পারে Thread। আমি এতে সন্তুষ্ট - যদিও GCDগটকা এবং সীমাবদ্ধতায় ভরা।
জাভাদবা

4

চেষ্টা করুন: এনএসরেকারসিভলক

একটি লক যা কোনও অচলাবস্থার কারণ ছাড়াই একই থ্রেড দ্বারা একাধিকবার অধিগ্রহণ করা যেতে পারে।

let lock = NSRecursiveLock()

func f() {
    lock.lock()
    //Your Code
    lock.unlock()
}

func f2() {
    lock.lock()
    defer {
        lock.unlock()
    }
    //Your Code
}

2

চিত্র আমি আমার সুইফট 5 বাস্তবায়ন পোস্ট করব, পূর্বের উত্তরগুলির তুলনায় তৈরি। ধন্যবাদ বন্ধুরা! আমি এটির সাথে একটি মানও ফিরিয়ে দেওয়া সহায়ক বলে মনে করেছি, সুতরাং আমার কাছে দুটি পদ্ধতি রয়েছে।

এখানে প্রথম তৈরি করার জন্য একটি সাধারণ বর্গ:

import Foundation
class Sync {
public class func synced(_ lock: Any, closure: () -> ()) {
        objc_sync_enter(lock)
        defer { objc_sync_exit(lock) }
        closure()
    }
    public class func syncedReturn(_ lock: Any, closure: () -> (Any?)) -> Any? {
        objc_sync_enter(lock)
        defer { objc_sync_exit(lock) }
        return closure()
    }
}

তারপরে যদি কোনও ফেরতের মান প্রয়োজন হয় তবে এটি এর মতো ব্যবহার করুন:

return Sync.syncedReturn(self, closure: {
    // some code here
    return "hello world"
})

বা:

Sync.synced(self, closure: {
    // do some work synchronously
})

চেষ্টা করুন public class func synced<T>(_ lock: Any, closure: () -> T), অকার্যকর এবং অন্য কোনও ধরণের উভয়ের জন্যই কাজ করে। রেগ্রোস স্টাফও রয়েছে।
এইচএনএইচ

@ রেগরোজ স্টাফ বলতে কী বোঝ? এছাড়াও যদি আপনি জেনেরিক পদ্ধতিতে <T> টাইপের সাথে একটি উদাহরণ কল ভাগ করতে ইচ্ছুক হন তবে এটি উত্তরটি আপডেট করতে সহায়তা করবে - আপনি পছন্দ করেন যেখানে আপনি যাচ্ছেন তা আমার পছন্দ হয়।
জেফ

রিথ্রোস, রিগ্রোস নয়, এসআরজেজ
এইচএনএম

1

বিস্তারিত

xCode 8.3.1, দ্রুত 3.1

কার্য

বিভিন্ন থ্রেড (async) থেকে লেখার মান পড়ুন।

কোড

class AsyncObject<T>:CustomStringConvertible {
    private var _value: T
    public private(set) var dispatchQueueName: String

    let dispatchQueue: DispatchQueue

    init (value: T, dispatchQueueName: String) {
        _value = value
        self.dispatchQueueName = dispatchQueueName
        dispatchQueue = DispatchQueue(label: dispatchQueueName)
    }

    func setValue(with closure: @escaping (_ currentValue: T)->(T) ) {
        dispatchQueue.sync { [weak self] in
            if let _self = self {
                _self._value = closure(_self._value)
            }
        }
    }

    func getValue(with closure: @escaping (_ currentValue: T)->() ) {
        dispatchQueue.sync { [weak self] in
            if let _self = self {
                closure(_self._value)
            }
        }
    }


    var value: T {
        get {
            return dispatchQueue.sync { _value }
        }

        set (newValue) {
            dispatchQueue.sync { _value = newValue }
        }
    }

    var description: String {
        return "\(_value)"
    }
}

ব্যবহার

print("Single read/write action")
// Use it when when you need to make single action
let obj = AsyncObject<Int>(value: 0, dispatchQueueName: "Dispatch0")
obj.value = 100
let x = obj.value
print(x)

print("Write action in block")
// Use it when when you need to make many action
obj.setValue{ (current) -> (Int) in
    let newValue = current*2
    print("previous: \(current), new: \(newValue)")
    return newValue
}

সম্পূর্ণ নমুনা

এক্সটেনশন ডিসপ্যাচগ্রুপ

extension DispatchGroup {

    class func loop(repeatNumber: Int, action: @escaping (_ index: Int)->(), completion: @escaping ()->()) {
        let group = DispatchGroup()
        for index in 0...repeatNumber {
            group.enter()
            DispatchQueue.global(qos: .utility).async {
                action(index)
                group.leave()
            }
        }

        group.notify(queue: DispatchQueue.global(qos: .userInitiated)) {
            completion()
        }
    }
}

ক্লাস ভিউ কন্ট্রোলার

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        //sample1()
        sample2()
    }

    func sample1() {
        print("=================================================\nsample with variable")

        let obj = AsyncObject<Int>(value: 0, dispatchQueueName: "Dispatch1")

        DispatchGroup.loop(repeatNumber: 5, action: { index in
            obj.value = index
        }) {
            print("\(obj.value)")
        }
    }

    func sample2() {
        print("\n=================================================\nsample with array")
        let arr = AsyncObject<[Int]>(value: [], dispatchQueueName: "Dispatch2")
        DispatchGroup.loop(repeatNumber: 15, action: { index in
            arr.setValue{ (current) -> ([Int]) in
                var array = current
                array.append(index*index)
                print("index: \(index), value \(array[array.count-1])")
                return array
            }
        }) {
            print("\(arr.value)")
        }
    }
}

1

সুইফটের সম্পত্তি র‌্যাপারগুলির সাথে, আমি এখন এটি ব্যবহার করছি:

@propertyWrapper public struct NCCSerialized<Wrapped> {
    private let queue = DispatchQueue(label: "com.nuclearcyborg.NCCSerialized_\(UUID().uuidString)")

    private var _wrappedValue: Wrapped
    public var wrappedValue: Wrapped {
        get { queue.sync { _wrappedValue } }
        set { queue.sync { _wrappedValue = newValue } }
    }

    public init(wrappedValue: Wrapped) {
        self._wrappedValue = wrappedValue
    }
}

তারপরে আপনি ঠিক করতে পারেন:

@NCCSerialized var foo: Int = 10

অথবা

@NCCSerialized var myData: [SomeStruct] = []

তারপরে আপনি যেমনটি চান তেমন চলক অ্যাক্সেস করুন।


1
আমি এই সমাধানটি পছন্দ করি, তবে জনগণের দামের বিষয়ে কৌতূহল ছিল @ ডেকোরটিং করার পরে যেহেতু এটির DispatchQueueব্যবহারকারীর কাছ থেকে লুকানো রয়েছে তা তৈরি করার পার্শ্ব প্রতিক্রিয়া রয়েছে । আমি আমার মনকে নিশ্চিন্ত করার জন্য এই এসও রেফারেন্সটি পেয়েছি: stackoverflow.com/a/35022486/1060314
অ্যাডাম ভেন্টুরেেলা

সম্পত্তির মোড়ক নিজেই বেশ হালকা - কেবল একটি কাঠামো, সুতরাং, আপনি তৈরি করতে পারেন সবচেয়ে হালকা জিনিসগুলির মধ্যে একটি। যদিও DispatchQueue লিঙ্কের জন্য ধন্যবাদ। আমি আমার মনের পেছনে ক্যু.সাইঙ্ক মোড়ানোর বিপরীতে অন্যান্য সমাধানগুলি (এবং কোনও সারি নয়) এর বিষয়ে কিছু কার্য সম্পাদনের পরীক্ষা করেছি, তবে তা করে নি।
ড্রয়স্টার

1

উপসংহারে, এখানে আরও সাধারণ উপায় দিন যা রিটার্ন মান বা অকার্যকর, এবং নিক্ষেপ অন্তর্ভুক্ত

import Foundation

extension NSObject {


    func synchronized<T>(lockObj: AnyObject!, closure: () throws -> T) rethrows ->  T
    {
        objc_sync_enter(lockObj)
        defer {
            objc_sync_exit(lockObj)
        }

        return try closure()
    }


}

0

লকগুলি দিয়ে কেন এটি কঠিন এবং ঝামেলা সৃষ্টি করে? ডিসপ্যাচ বাধা ব্যবহার করুন।

একটি প্রেরণ বাধা একটি সমবর্তী সারির মধ্যে একটি সিঙ্ক্রোনাইজেশন পয়েন্ট তৈরি করে।

এটি চলমান অবস্থায়, সারিবদ্ধ অন্য কোনও ব্লক চালানোর অনুমতি নেই, এটি সমবর্তী এবং অন্যান্য কোরগুলি উপলভ্য থাকলেও।

যদি এটি একচেটিয়া (লিখন) লকের মতো মনে হয় তবে তা। অ-বাধা ব্লকগুলি ভাগ করা (পঠিত) লক হিসাবে ভাবা যেতে পারে।

যতক্ষণ সম্পদের সমস্ত অ্যাক্সেস সারির মাধ্যমে সঞ্চালিত হয়, বাধাগুলি খুব সস্তা সিঙ্ক্রোনাইজেশন সরবরাহ করে।


2
আমি বলতে চাইছি আপনি অ্যাক্সেসকে সিঙ্ক্রোনাইজ করার জন্য একটি জিসিডি ক্যু ব্যবহার করছেন, তবে এটি মূল প্রশ্নের মধ্যে উল্লেখ করা হয়নি। এবং একটি বাধা কেবল একটি সামনের সারির সাথে প্রয়োজনীয় - আপনি কোনও লক অনুকরণ করতে পারস্পরিকভাবে বাদ দেওয়া ব্লকগুলি সারি করার জন্য একটি সিরিয়াল সারি ব্যবহার করতে পারেন।
বিল 19

আমার প্রশ্ন, কেন একটি লক অনুকরণ? আমি যা পড়েছি তা থেকে, একটি সারির মধ্যে ওভারহেড বনাম বাধা থাকার কারণে লকগুলি নিরুৎসাহিত করা হয়।
ফ্রেডেরিক সি। লি

0

আইওরোবারির উপর ভিত্তি করে একটি উপ-শ্রেণীর কেস পরীক্ষা করুন

class Foo: NSObject {
    func test() {
        print("1")
        objc_sync_enter(self)
        defer {
            objc_sync_exit(self)
            print("3")
        }

        print("2")
    }
}


class Foo2: Foo {
    override func test() {
        super.test()

        print("11")
        objc_sync_enter(self)
        defer {
            print("33")
            objc_sync_exit(self)
        }

        print("22")
    }
}

let test = Foo2()
test.test()

আউটপুট:

1
2
3
11
22
33

0

বর্তমান থ্রেডকে অবরুদ্ধ না করে, প্রেরণ_বারি_স্যানসিচ হ'ল আরও ভাল উপায়।

প্রেরণ_বাড়ি_কেন্দ্র (অ্যাক্সেসকিউ, {অভিধান [অবজেক্ট.আইডি] = অবজেক্ট})


-5

আরেকটি পদ্ধতি হ'ল একটি সুপারক্লাস তৈরি করা এবং তারপরে এটি উত্তরাধিকারী। এইভাবে আপনি আরও সরাসরি জিসিডি ব্যবহার করতে পারেন

class Lockable {
    let lockableQ:dispatch_queue_t

    init() {
        lockableQ = dispatch_queue_create("com.blah.blah.\(self.dynamicType)", DISPATCH_QUEUE_SERIAL)
    }

    func lock(closure: () -> ()) {
        dispatch_sync(lockableQ, closure)
    }
}


class Foo: Lockable {

    func boo() {
        lock {
            ....... do something
        }
    }

9
-1 উত্তরাধিকার বর্ধমান সংযোগের বিনিময়ে আপনাকে উপ-টাইপ পলিমারফিজম দেয়। আপনার যদি পূর্বের প্রয়োজন না হয় তবে পরে এড়িয়ে চলুন। অলসতা করবেন না। কোড পুনরায় ব্যবহারের জন্য রচনা পছন্দ করুন।
জানো
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.