स्विफ्ट में बैकग्राउंड थ्रेड का उपयोग कैसे करें?


329

स्विफ्ट में थ्रेडिंग का उपयोग कैसे करें?

dispatchOnMainThread:^{

    NSLog(@"Block Executed On %s", dispatch_queue_get_label(dispatch_get_current_queue()));

}];

आपको कौन सा भाग परिवर्तित करने में परेशानी होती है?
nschum

2
आपके पास ]अंतिम पंक्ति में अर्धविराम से पहले क्यों है ?
आकाशवाणी

3
यह उपयोगी होगा यदि आप समझाते हैं कि आप कहाँ फंस गए हैं या आपको किसकी मदद चाहिए।
nsuinteger

4
आपको सही उत्तर को स्वीकार करना चाहिए यदि यह वास्तव में आपकी मदद करता है, तो इससे अन्य को भी सही समाधान खोजने में मदद मिलेगी।
अमित सिंह

DispatchQueue.global(qos: .background).async { print("Run on background thread") DispatchQueue.main.async { print("We finished that.") // only back on the main thread, may you access UI: label.text = "Done." } }
अनुराग शर्मा

जवाबों:


708

स्विफ्ट 3.0+

स्विफ्ट 3.0 में बहुत कुछ आधुनिक किया गया है । बैकग्राउंड थ्रेड पर कुछ इस तरह दौड़ रहा है:

DispatchQueue.global(qos: .background).async {
    print("This is run on the background queue")

    DispatchQueue.main.async {
        print("This is run on the main queue, after the previous code in outer block")
    }
}

2.3 के माध्यम से 1.2 स्विफ्ट

let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
dispatch_async(backgroundQueue, {
    print("This is run on the background queue")

    dispatch_async(dispatch_get_main_queue(), { () -> Void in
        print("This is run on the main queue, after the previous code in outer block")
    })
})

प्री स्विफ्ट 1.2 - ज्ञात समस्या

1.1 स्विफ्ट के रूप में Apple ने कुछ संशोधनों के बिना उपरोक्त वाक्य रचना का समर्थन नहीं किया। पासिंग QOS_CLASS_BACKGROUNDवास्तव में काम नहीं किया, इसके बजाय उपयोग करें Int(QOS_CLASS_BACKGROUND.value)

अधिक जानकारी के लिए सेब का दस्तावेज़ीकरण देखें


23
और अगर कोई सिंटैक्स की तरह अधिक स्विफ्ट चाहता है, तो मैंने Async बनाया है जो कुछ चीनी को सिंटैक्स में जोड़ता है जैसेAsync.background {}
Tobiasdm

मैं xCode 6.0.1 और ios 8. में आपके कोड का उपयोग कर रहा हूं। यह "QOS_CLASS_BACKGROUND" रिटर्न वर्ग के रूप में त्रुटि देता है और यह टाइप UInt32 का होता है और "dispatch_get_global_queue" के लिए 1st की आवश्यकता होती है क्योंकि इंट में इसलिए टाइप टाइप त्रुटि आ रही है।
जालक पटेल

तो Xcode 6.1.1 में मुझे केवल सादे सरल "QOS_CLASS_BACKGROUND" का उपयोग करने के लिए कोई त्रुटि नहीं मिल रही है। क्या यह तय है?
लुकास गूसेन

@LucasGoossen हां, यह तय हो गया है। मैंने तदनुसार पोस्ट अपडेट की है।
22

1
@NikitaPronchik क्या यह उत्तर से स्पष्ट नहीं है? इसके लिए एक संपादन करने के लिए स्वतंत्र महसूस हो रहा है।
टोबैसडैम

123

सबसे अच्छा अभ्यास एक पुन: प्रयोज्य फ़ंक्शन को परिभाषित करना है जिसे कई बार एक्सेस किया जा सकता है।

पुन: प्रयोज्य समारोह:

जैसे कि AppDelegate.swift एक ग्लोबल फंक्शन के रूप में।

func backgroundThread(_ delay: Double = 0.0, background: (() -> Void)? = nil, completion: (() -> Void)? = nil) {
    dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.value), 0)) {
        background?()

        let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
        dispatch_after(popTime, dispatch_get_main_queue()) {
            completion?()
        }
    }
}

नोट: स्विफ्ट 2.0 में, की जगह QOS_CLASS_USER_INITIATED.value साथ ऊपर QOS_CLASS_USER_INITIATED.rawValue बजाय

उपयोग:

ए। 3 सेकंड की देरी से पृष्ठभूमि में एक प्रक्रिया चलाने के लिए:

    backgroundThread(3.0, background: {
            // Your background function here
    })

B. पृष्ठभूमि में एक प्रक्रिया को चलाने के लिए फिर अग्रभूमि में एक पूर्णता चलाएं:

    backgroundThread(background: {
            // Your function here to run in the background
    },
    completion: {
            // A function to run in the foreground when the background thread is complete
    })

C. 3 सेकंड देरी से - पृष्ठभूमि पैरामीटर के बिना पूरा होने वाले पैरामीटर का उपयोग करें:

    backgroundThread(3.0, completion: {
            // Your delayed function here to be run in the foreground
    })

1
अच्छा स्निपेट, सही उत्तर होना चाहिए। @ डेल क्लिफोर्ड
LoVo

निम्न स्तर की C लाइब्रेरी से पुराने समय की GCD विधियों तक पहुँचने के लिए शानदार उच्च स्तरीय आधुनिक स्विफ्ट-वाई दृष्टिकोण। स्विफ्ट में मानक आना चाहिए।
क्रेग ग्रुमाइट

2
बहुत अच्छा। क्या आप पुष्टि करेंगे, देरी केवल पूर्ण ब्लॉक के लिए काम करती है। तो इसका मतलब है कि ए में देरी का कोई प्रभाव नहीं है, और पृष्ठभूमि ब्लॉक देरी के बिना तुरंत निष्पादित करता है।
ObjectiveTC

1
आप कुछ हद तक तेजी से वाक्यविन्यास के if(background != nil){ background!(); }साथ बदलने में सक्षम होना चाहिए background?()?
साइमन बेंग्सटन

1
क्या आप इसे स्विफ्ट 3 के लिए अपडेट कर सकते हैं? ऑटो कनवर्टर ने इसे चालू कर दिया DispatchQueue.global(priority: Int(DispatchQoS.QoSClass.userInitiated.rawValue)).async {लेकिन यह एक त्रुटि की तरह है cannot invoke initializer for type 'Int' with an argument list of type '(qos_class_t)'। एक काम कर समाधान यहाँ पाया जाता है ( DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated).async)।
देव-इल

111

स्विफ्ट 5 में डैन ब्यूलियू का जवाब (स्विफ्ट 3.0.1 के बाद से भी काम कर रहा है)।

स्विफ्ट 5.0.1

extension DispatchQueue {

    static func background(delay: Double = 0.0, background: (()->Void)? = nil, completion: (() -> Void)? = nil) {
        DispatchQueue.global(qos: .background).async {
            background?()
            if let completion = completion {
                DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: {
                    completion()
                })
            }
        }
    }

}

प्रयोग

DispatchQueue.background(delay: 3.0, background: {
    // do something in background
}, completion: {
    // when background job finishes, wait 3 seconds and do something in main thread
})

DispatchQueue.background(background: {
    // do something in background
}, completion:{
    // when background job finished, do something in main thread
})

DispatchQueue.background(delay: 3.0, completion:{
    // do something in main thread after 3 seconds
})

कमाल है, स्विफ्ट 3.0.1 प्रारूप में इतनी अच्छी तरह से अपडेट करने के लिए धन्यवाद!
डेल क्लिफोर्ड

1
मैं किसी भी जीवित व्यक्ति से अधिक एक्सटेंशन का उपयोग करता हूं। लेकिन मूल से अलग नहीं है, एक विस्तार का उपयोग करने में एक वास्तविक खतरा है!
fattie

@ बहुत सुंदर, क्या यह संभव है कि एक पूरा हैंडलर जोड़ने के लिए जब 4 एसिंक्स कॉल खत्म हो जाए? मुझे इसका थोड़ा-सा विषय पता है।
eonist

1
हाँ, उस लिंक को भूल जाओ। आप सभी की जरूरत है एक प्रेषण समूह है - यह बहुत आसान है; चिंता की कोई बात नहीं है !
फेटी

1
@DilipJangid आप तब तक नहीं कर सकते, जब तक कि backgroundक्लोजर में आपका काम बहुत लंबा (~ = अनंत) न हो जाए। यह विधि एक परिमित समय तक बनी रहती है: जिस समय आपकी पृष्ठभूमि की नौकरी को निष्पादित करने की आवश्यकता होती है। इसलिए, completionजैसे ही आपका बैकग्राउंड जॉब एक्जीक्यूशन टाइम + डिले हो जाएगा , क्लोजर को कॉल किया जाएगा।
frouo

42

स्विफ्ट 3 संस्करण

स्विफ्ट 3 DispatchQueueकतारों और धागों के प्रबंधन के लिए नए वर्ग का उपयोग करता है । आपके द्वारा उपयोग किए जाने वाले बैकग्राउंड थ्रेड पर कुछ चलाने के लिए:

let backgroundQueue = DispatchQueue(label: "com.app.queue", qos: .background)
backgroundQueue.async {
    print("Run on background thread")
}

या यदि आप कोड की दो लाइनों में कुछ चाहते हैं:

DispatchQueue.global(qos: .background).async {
    print("Run on background thread")

    DispatchQueue.main.async {
        print("We finished that.")
        // only back on the main thread, may you access UI:
        label.text = "Done."
    }
}

आप इस ट्यूटोरियल में स्विफ्ट 3 में जीडीसी के बारे में कुछ गहराई से जानकारी प्राप्त कर सकते हैं ।


कहा च। चूँकि आपका उत्तर सबसे अच्छा है, मैंने कोड की एक पंक्ति में दिखाया कि आप कैसे "जब वापस कॉल करें"। बेझिझक या संपादित करें, चीयर्स करने के लिए स्वतंत्र महसूस करें
Fattie

35

से जेमिसन Quave के ट्यूटोरियल

स्विफ्ट 2

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
    //All stuff here
})

3
स्पष्टीकरण के लिए, स्वीकृत उत्तर के बजाय इसका उपयोग क्यों किया जाएगा? क्या यह सिर्फ एक पुराना एपीआई है?
सायरन

1
@ सीन मुझे लगता है कि यह ऐप का समर्थन करने वाले ऐप के लिए बहुत उपयोगी होगा <iOS 8.
bperdue

मैं प्रक्रियाओं का उपयोग करने के लिए आईओएस 8.2 के लिए इसका उपयोग करता हूं।
--ολ15ν.λαβέ

DISPATCH_QUEUE_PRIORITY_DEFAULT QOS_CLASS_DEFAULT पर निर्भर करता है। इसलिए मुझे लगता है कि आप कह सकते हैं कि यह अधिक उच्च स्तर / स्वीकृत वाक्यविन्यास है।
पोस्टकोडिज़्म

34

स्विफ्ट 4.2 और एक्सकोड 10.1 में

हमारे पास तीन प्रकार की कतारें हैं:

1. मुख्य कतार: मुख्य कतार एक धारावाहिक कतार है जो प्रणाली द्वारा बनाई गई है और आवेदन मुख्य धागे से जुड़ी है।

2. वैश्विक कतार: वैश्विक कतार एक समवर्ती कतार है जिसे हम कार्यों की प्राथमिकता के संबंध में अनुरोध कर सकते हैं।

3. कस्टम कतार: उपयोगकर्ता द्वारा बनाया जा सकता है। क्वालिटी ऑफ़ सर्विस प्रॉपर्टी (QoS) निर्दिष्ट करके कस्टम समवर्ती कतारें हमेशा वैश्विक कतारों में से एक में मैप की जाती हैं।

DispatchQueue.main//Main thread
DispatchQueue.global(qos: .userInitiated)// High Priority
DispatchQueue.global(qos: .userInteractive)//High Priority (Little Higher than userInitiated)
DispatchQueue.global(qos: .background)//Lowest Priority
DispatchQueue.global(qos: .default)//Normal Priority (after High but before Low)
DispatchQueue.global(qos: .utility)//Low Priority
DispatchQueue.global(qos: .unspecified)//Absence of Quality

इन सभी कतारों को दो तरह से अंजाम दिया जा सकता है

1. तुल्यकालिक निष्पादन

2. अतुल्यकालिक निष्पादन

DispatchQueue.global(qos: .background).async {
    // do your job here
    DispatchQueue.main.async {
        // update ui here
    }
}

//Perform some task and update UI immediately.
DispatchQueue.global(qos: .userInitiated).async {  
    // Perform task
    DispatchQueue.main.async {  
        // Update UI
        self.tableView.reloadData()  
    }
}

//To call or execute function after some time
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    //Here call your function
}

//If you want to do changes in UI use this
DispatchQueue.main.async(execute: {
    //Update UI
    self.tableView.reloadData()
})

AppCoda से: https://www.appcoda.com/grand-central-dispatch/

//This will print synchronously means, it will print 1-9 & 100-109
func simpleQueues() {
    let queue = DispatchQueue(label: "com.appcoda.myqueue")

    queue.sync {
        for i in 0..<10 {
            print("🔴", i)
        }
    }

    for i in 100..<110 {
        print("Ⓜ️", i)
    }
}

//This will print asynchronously 
func simpleQueues() {
    let queue = DispatchQueue(label: "com.appcoda.myqueue")

    queue.async {
        for i in 0..<10 {
            print("🔴", i)
        }
    }

    for i in 100..<110 {
        print("Ⓜ️", i)
    }
}

1
थ्रेड्स के लिए सबसे अच्छा ट्यूटोरियल medium.com/@gabriel_lewis/…
iOS

जब आप का उपयोग मैं कोई भी परिवर्तन नहीं देखा .background क्यूओएस या .userInitiatedलेकिन मेरे लिए इसके साथ बाहर काम किया.background
जंग

24

स्विफ्ट 4.x

इसे कुछ फ़ाइल में रखें:

func background(work: @escaping () -> ()) {
    DispatchQueue.global(qos: .userInitiated).async {
        work()
    }
}

func main(work: @escaping () -> ()) {
    DispatchQueue.main.async {
        work()
    }
}

और फिर उसे कॉल करें जहाँ आपको ज़रूरत है:

background {
     //background job
     main {
       //update UI (or what you need to do in main thread)
     }
}

22

आपको उन परिवर्तनों को अलग करना होगा जिन्हें आप UI पर चलाने के लिए अद्यतन से पृष्ठभूमि में चलाना चाहते हैं:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
    // do your task

    dispatch_async(dispatch_get_main_queue()) {
        // update some UI
    }
}

तो dispatch_async(dispatch_get_main_queue()) { // update some UI }कहा जाता है जब पृष्ठभूमि कथन (बाहरी ब्लॉक) निष्पादित किया जाता है?
जस्ट

यह केवल स्विफ्ट 2.3 और उससे नीचे के लिए नहीं है?
सुरज

9

हालांकि अच्छे जवाब, वैसे भी मैं अपने ऑब्जेक्ट ओरिएंटेड सॉल्यूशन को स्विफ्ट 5 की तारीख तक साझा करना चाहता हूं ।

कृपया इसे देखें: AsyncTask

वैचारिक रूप से Android के AsyncTask से प्रेरित होकर, मैंने स्विफ्ट में अपनी कक्षा लिखी है

AsyncTask UI थ्रेड का उचित और आसान उपयोग सक्षम करता है। यह वर्ग पृष्ठभूमि संचालन करने और UI थ्रेड पर परिणाम प्रकाशित करने की अनुमति देता है।

यहाँ कुछ उपयोग उदाहरण हैं

उदाहरण 1 -

AsyncTask(backgroundTask: {(p:String)->Void in//set BGParam to String and BGResult to Void
        print(p);//print the value in background thread
    }).execute("Hello async");//execute with value 'Hello async'

उदाहरण 2 -

let task2=AsyncTask(beforeTask: {
           print("pre execution");//print 'pre execution' before backgroundTask
        },backgroundTask:{(p:Int)->String in//set BGParam to Int & BGResult to String
            if p>0{//check if execution value is bigger than zero
               return "positive"//pass String "poitive" to afterTask
            }
            return "negative";//otherwise pass String "negative"
        }, afterTask: {(p:String) in
            print(p);//print background task result
    });
    task2.execute(1);//execute with value 1

इसके 2 सामान्य प्रकार हैं:

  • BGParam - निष्पादन पर कार्य को भेजे गए पैरामीटर का प्रकार।
  • BGResult - पृष्ठभूमि संगणना के परिणाम का प्रकार।

    जब आप एक AsyncTask बनाते हैं, तो आप उन सभी प्रकारों को ले सकते हैं जिन्हें आपको पृष्ठभूमि कार्य से बाहर और अंदर जाने की आवश्यकता होती है, लेकिन यदि आपको उन प्रकारों की आवश्यकता नहीं है, तो आप इसे केवल इसे सेट करने के साथ अप्रयुक्त के रूप में चिह्नित कर सकते हैं: Voidया छोटे सिंटैक्स के साथ:()

जब एक अतुल्यकालिक कार्य निष्पादित किया जाता है, तो यह 3 चरणों से गुजरता है:

  1. beforeTask:()->Void कार्य निष्पादित होने से ठीक पहले UI थ्रेड पर लागू किया गया।
  2. backgroundTask: (param:BGParam)->BGResult तुरंत बाद पृष्ठभूमि थ्रेड पर लागू किया गया
  3. afterTask:(param:BGResult)->Void पृष्ठभूमि कार्य के परिणाम के साथ UI थ्रेड पर लागू किया गया

4
यह मेरे लिए अद्भुत काम करता है। अच्छा काम है, इसे गीथूब पर क्यों नहीं रखा?
३६ बाइ डिजाइन

8

चूंकि ओपी प्रश्न पहले ही उत्तर दिया जा चुका है, इसलिए मैं केवल कुछ गति विचार जोड़ना चाहता हूं:

मैं विशेष रूप से iPhone X पर .background थ्रेड प्राथमिकता के साथ कार्य चलाने की अनुशंसा नहीं करता जहाँ कार्य कम पावर कोर पर आवंटित किया गया लगता है।

यहाँ एक कम्प्यूटेशनल रूप से गहन फ़ंक्शन से कुछ वास्तविक डेटा है जो XML फ़ाइल (बफ़रिंग के साथ) से पढ़ता है और डेटा प्रक्षेप को निष्पादित करता है:

डिवाइस का नाम / .background / .utility / .default / .userInitiated / .userInteractive

  1. iPhone X: 18.7 / 6.3s / 1.8s / 1.8s / 1.8s
  2. iPhone 7: 4.6s / 3.1s / 3.0s / 2.8 / 2.6
  3. iPhone 5s: 7.3s / 6.1s / 4.0s / 4.0s / 3.8s

ध्यान दें कि डेटा सेट सभी उपकरणों के लिए समान नहीं है। यह iPhone X में सबसे बड़ा और iPhone 5s पर सबसे छोटा है।


4

स्विफ्ट 5

इसे आसान बनाने के लिए, इस सामग्री के साथ एक फ़ाइल "DispatchQueue + Extensions.swift" बनाएं:

import Foundation

typealias Dispatch = DispatchQueue

extension Dispatch {

    static func background(_ task: @escaping () -> ()) {
        Dispatch.global(qos: .background).async {
            task()
        }
    }

    static func main(_ task: @escaping () -> ()) {
        Dispatch.main.async {
            task()
        }
    }
}

उपयोग:

Dispatch.background {
    // do stuff

    Dispatch.main { 
        // update UI
    }
}

2

ग्रैंड सेंट्रल डिस्पैच का उपयोग हमारे iOS ऐप में मल्टीटास्किंग को संभालने के लिए किया जाता है।

आप इस कोड का उपयोग कर सकते हैं

// Using time interval

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+1) {
    print("Hello World")
}

// Background thread
queue.sync {
     for i in 0..<10 {
          print("Hello", i)
     }
}

// Main thread
for i in 20..<30 {
     print("Hello", i)
}

अधिक जानकारी इस लिंक का उपयोग करें: https://www.programminghub.us/2018/07/integrate-dispatcher-in-swift.html


2

धागे के लिए बहु प्रयोजन समारोह

public enum QueueType {
        case Main
        case Background
        case LowPriority
        case HighPriority

        var queue: DispatchQueue {
            switch self {
            case .Main:
                return DispatchQueue.main
            case .Background:
                return DispatchQueue(label: "com.app.queue",
                                     qos: .background,
                                     target: nil)
            case .LowPriority:
                return DispatchQueue.global(qos: .userInitiated)
            case .HighPriority:
                return DispatchQueue.global(qos: .userInitiated)
            }
        }
    }

    func performOn(_ queueType: QueueType, closure: @escaping () -> Void) {
        queueType.queue.async(execute: closure)
    }

इसका उपयोग करें जैसे:

performOn(.Background) {
    //Code
}

1

मैं वास्तव में डैन ब्यूलियू के उत्तर को पसंद करता हूं, लेकिन यह स्विफ्ट 2.2 के साथ काम नहीं करता है और मुझे लगता है कि हम उन बुरा मजबूर एक्सट्रैप्स से बच सकते हैं!

func backgroundThread(delay: Double = 0.0, background: (() -> Void)? = nil, completion: (() -> Void)? = nil) {

    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) {

        background?()

        if let completion = completion{
            let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
            dispatch_after(popTime, dispatch_get_main_queue()) {
                completion()
            }
        }
    }
}

0
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), {
    // Conversion into base64 string
    self.uploadImageString =  uploadPhotoDataJPEG.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.EncodingEndLineWithCarriageReturn)
})

-3

स्विफ्ट 4.2 में यह काम करता है।

import Foundation

class myThread: Thread
{
    override func main() {
        while(true) {
            print("Running in the Thread");
            Thread.sleep(forTimeInterval: 4);
        }
    }
}

let t = myThread();
t.start();

while(true) {
    print("Main Loop");
    sleep(5);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.