Background Thread — निष्पादन की एक थ्रेड जो उपयोगकर्ता इंटरफ़ेस से जुड़ी नहीं है, लंबे समय तक चलने वाले कार्यों के लिए डिज़ाइन की गई है: नेटवर्क अनुरोध, फ़ाइल संचालन, JSON पार्सिंग, इमेज कम्प्रेशन, एन्क्रिप्शन और डेटाबेस क्वेरी। iOS में, पृष्ठभूमि थ्रेड्स को GCD (DispatchQueue.global) और OperationQueue के माध्यम से प्रबंधित किया जाता है; Android में, Executors, WorkManager और Kotlin Coroutines (Dispatchers.IO, Dispatchers.Default) के माध्यम से। Apple DispatchQueue दस्तावेज़ीकरण के अनुसार, पृष्ठभूमि कार्य पूरा होने के बाद, परिणाम इंटरफ़ेस को अपडेट करने के लिए Main Thread पर वापस लौटाया जाना चाहिए।
मुख्य बिंदु
Background Thread — एप्लिकेशन में कोई भी थ्रेड जो Main Thread नहीं है और उसके पास UI तक पहुंच नहीं है। इसका काम मुख्य थ्रेड को भारी कार्यों से मुक्त करना है ताकि इंटरफ़ेस प्रतिक्रियाशील बना रहे। ऑपरेटिंग सिस्टम पृष्ठभूमि थ्रेड्स को CPU कोर में वितरित करता है, जिससे कई कार्य समानांतर में चल सकते हैं। iOS स्वचालित रूप से GCD के माध्यम से थ्रेड पूल का प्रबंधन करता है, Android Java Executors पूल के माध्यम से।
Main Thread के विपरीत, जो घटनाओं को क्रमिक रूप से (एक के बाद एक) संसाधित करता है, पृष्ठभूमि थ्रेड्स समानांतर में चल सकते हैं, केवल CPU कोर की संख्या से सीमित। उदाहरण के लिए, 8-कोर डिवाइस पर बिना महत्वपूर्ण धीमापन के 8 समानांतर पृष्ठभूमि कार्य चलाए जा सकते हैं। हालांकि, अत्यधिक संख्या में थ्रेड्स (सैकड़ों) thread starvation — कोर के लिए प्रतिस्पर्धा और संदर्भ स्विच (context switch) के बढ़ते ओवरहेड की ओर ले जाती है।
Quality of Service (QoS) — iOS तंत्र जो पृष्ठभूमि कार्य की प्राथमिकता निर्दिष्ट करने की अनुमति देता है। मान: .userInteractive (सबसे उच्च, लगभग Main Thread), .userInitiated (उपयोगकर्ता परिणाम की प्रतीक्षा कर रहा है), .default (मानक), .utility (उपयोगकर्ता सीधे प्रतीक्षा नहीं कर रहा), .background (सबसे निम्न, सिंक और इंडेक्सिंग के लिए)। Android में, समतुल्य Thread.setPriority() 1 से 10 तक है, लेकिन Android थ्रेड प्राथमिकताओं के समूह प्रबंधन के लिए cgroups का भी उपयोग करता है।
DispatchQueue.global(qos:) — iOS में पृष्ठभूमि कतार प्राप्त करने का प्राथमिक तरीका। GCD (Grand Central Dispatch) स्वचालित रूप से एक थ्रेड पूल बनाता है और कोर में कार्य वितरित करता है। DispatchQueue.global(qos: .background).async {} कॉल सबसे कम प्राथमिकता वाली पृष्ठभूमि कतार में एक ब्लॉक भेजता है। उन कार्यों के लिए जिनके परिणाम तुरंत चाहिए, .userInitiated या .utility का उपयोग करें।
OperationQueue — GCD के ऊपर एक उच्च-स्तरीय एब्स्ट्रैक्शन जो संचालनों के बीच निर्भरताएं, अधिकतम समवर्ती संचालन संख्या (maxConcurrentOperationCount) और प्राथमिकताएं निर्धारित करने की अनुमति देता है। OperationQueue जटिल मल्टीटास्किंग श्रृंखलाओं के लिए सुविधाजनक है: फ़ाइल डाउनलोड करें → अनज़िप करें → कैश में सहेजें। डिफ़ॉल्ट रूप से, OperationQueue पृष्ठभूमि थ्रेड्स का उपयोग करता है जब तक कि अन्यथा निर्दिष्ट न किया गया हो।
import UIKit
class ImageDownloader {
func downloadImagesSequentially() {
let urls = ["https://example.com/1.png", "https://example.com/2.png"]
// maxConcurrentOperationCount = 2 के साथ OperationQueue
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 2
queue.qualityOfService = .utility
for urlString in urls {
queue.addOperation {
guard let url = URL(string: urlString),
let data = try? Data(contentsOf: url)
else { return }
DispatchQueue.main.async {
print("लोड किया गया: \(url.lastPathComponent)")
}
}
}
}
// GCD: विभिन्न QoS के साथ वैश्विक पृष्ठभूमि कतार
func backgroundTaskWithQoS() {
DispatchQueue.global(qos: .userInitiated).async {
// उच्च प्राथमिकता — उपयोगकर्ता परिणाम की प्रतीक्षा कर रहा है
let result = self.heavyComputation()
DispatchQueue.main.async {
self.showResult(result)
}
}
}
private func heavyComputation() -> String {
Thread.sleep(forTimeInterval: 2) // कार्य का अनुकरण
return "गणना परिणाम"
}
private func showResult(_ result: String) {
print("Result on Main: \(result)")
}
}
उदाहरण में, OperationQueue qualityOfService = .utility के माध्यम से पृष्ठभूमि QoS के साथ दो इमेज समानांतर में लोड करता है (maxConcurrentOperationCount = 2)। GCD विधि backgroundTaskWithQoS .userInitiated के साथ एक वैश्विक कतार का उपयोग करती है जिसके परिणाम की उपयोगकर्ता प्रतीक्षा कर रहा है। दोनों दृष्टिकोण UI अपडेट करने के लिए DispatchQueue.main पर वापस लौटकर समाप्त होते हैं — यह iOS में एक अनिवार्य आवश्यकता है।
GCD दो प्रकार की कतारों का समर्थन करता है: serial (अनुक्रमिक) और concurrent (समवर्ती)। Serial कतारें एक के बाद एक कार्य निष्पादित करती हैं — यह बिना लॉक के साझा संसाधन (फ़ाइल, DB) तक पहुंचने के लिए सुविधाजनक है। Concurrent कतारें कार्यों को समानांतर में निष्पादित करती हैं, उन्हें उपलब्ध कोर में वितरित करती हैं। DispatchQueue.global हमेशा concurrent होती है। Serial कतार बनाने के लिए, DispatchQueue(label: "com.app.queue") का उपयोग करें।
Android पृष्ठभूमि थ्रेड्स के लिए कई स्तरों का एब्स्ट्रैक्शन प्रदान करता है। क्लासिक दृष्टिकोण java.util.concurrent.Executors.newFixedThreadPool(n) या Executors.newCachedThreadPool() है। आधुनिक दृष्टिकोण Kotlin Coroutines है जिसमें Dispatchers.IO (I/O के लिए: नेटवर्क, फ़ाइलें, DB) और Dispatchers.Default (CPU-गहन कार्यों के लिए: सॉर्टिंग, इमेज प्रोसेसिंग) शामिल हैं। WorkManager विलंबित और गारंटीकृत पृष्ठभूमि कार्यों के लिए है।
HandlerThread — अपने स्वयं के Looper (संदेश कतार) के साथ पृष्ठभूमि थ्रेड बनाने के लिए एक विशेष Android वर्ग। Executors के विपरीत, HandlerThread Handler के माध्यम से संदेश और Runnable भेजने की अनुमति देता है। इसका उपयोग उन संचालनों के लिए किया जाता है जिन्हें कतारबद्ध करने की आवश्यकता होती है (जैसे, अनुक्रमिक DB लेखन)। उपयोग के बाद, संसाधनों को मुक्त करने के लिए quit() या quitSafely() कॉल किया जाना चाहिए।
// Android: Executors और Coroutines Dispatchers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.concurrent.Executors
class DataRepository {
private val ioExecutor = Executors.newFixedThreadPool(4)
// Executors के माध्यम से क्लासिक दृष्टिकोण
fun loadDataLegacy(callback: (String) -> Unit) {
ioExecutor.execute {
val result = readFromFile()
val handler = android.os.Handler(android.os.Looper.getMainLooper())
handler.post { callback(result) }
}
}
// Coroutines के माध्यम से आधुनिक दृष्टिकोण
suspend fun loadDataCoroutines(): String {
return withContext(Dispatchers.IO) {
// फ़ाइल संचालन — पृष्ठभूमि पूल में निष्पादित हो रहा है
readFromFile()
}
// परिणाम स्वचालित रूप से Dispatchers.Main पर लौटता है
}
// Dispatchers.Default पर CPU-गहन कार्य
suspend fun processImage(pixels: IntArray): IntArray {
return withContext(Dispatchers.Default) {
// सॉर्टिंग, फ़िल्टरिंग — Default पूल पर निष्पादित हो रहा है
pixels.sortedArray()
}
}
private fun readFromFile(): String {
Thread.sleep(1000) // फ़ाइल से पढ़ने का अनुकरण
return "file_content"
}
fun cleanup() {
ioExecutor.shutdown()
}
}
DataRepository उदाहरण Android में पृष्ठभूमि थ्रेड्स के विकास को दर्शाता है। लीगेसी विधि loadDataLegacy Main Thread पर वापस लौटने के लिए Handler के साथ Executors.newFixedThreadPool(4) का उपयोग करती है। आधुनिक loadDataCoroutines withContext(Dispatchers.IO) का उपयोग करती है — coroutine थ्रेड को ब्लॉक किए बिना निष्पादन के दौरान निलंबित हो जाता है और स्वचालित रूप से Main Thread पर फिर से शुरू हो जाता है। Dispatchers.Default CPU-बाउंड संचालनों (सॉर्टिंग, फ़िल्टरिंग, डेटा ट्रांसफ़ॉर्मेशन) के लिए अनुशंसित है।
Kotlin Coroutines — थ्रेड्स के साथ काम करने का एक तरीका मात्र नहीं, बल्कि एक मौलिक रूप से भिन्न मॉडल: एसिंक्रोनस कार्य किसी विशिष्ट थ्रेड से बंधे नहीं होते और बिना ब्लॉक किए निलंबित हो सकते हैं। इसका मतलब है कि पृष्ठभूमि में रहते हुए, coroutine थ्रेड पर कब्जा नहीं करता बल्कि इसे अन्य कार्यों के लिए मुक्त करता है। निलंबन तंत्र 4–8 थ्रेड्स के पूल पर बिना thread starvation के सैकड़ों हजारों समवर्ती कार्य चलाने की अनुमति देता है।
तीन मुख्य डिस्पैचर: Dispatchers.Main (UI, एक थ्रेड), Dispatchers.IO (डिफ़ॉल्ट रूप से 64 थ्रेड ब्लॉकिंग संचालनों के लिए: नेटवर्क, फ़ाइलें, DB), Dispatchers.Default (CPU कोर की संख्या के बराबर, गहन गणनाओं के लिए)। withContext के माध्यम से उन्हें संयोजित करके, डेवलपर callbacks बनाए बिना थ्रेड्स के बीच स्विच करता है। withContext एक suspend फ़ंक्शन है जो कार्य पूरा होने तक नियंत्रण वापस नहीं करता।
// Coroutines: पृष्ठभूमि कार्यों की संरचना
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
suspend fun loadUserProfile(userId: String): UserProfile =
coroutineScope {
// विभिन्न स्रोतों से समानांतर डेटा लोडिंग
val user = async(Dispatchers.IO) { fetchUser(userId) }
val posts = async(Dispatchers.IO) { fetchPosts(userId) }
val avatar = async(Dispatchers.Default) {
processAvatar(fetchAvatar(userId))
}
// await() — सभी कार्य पूरा होने तक निलंबित रहता है
UserProfile(
user = user.await(),
posts = posts.await(),
avatar = avatar.await()
)
}
data class UserProfile(
val user: String,
val posts: List<String>,
val avatar: ByteArray
)
suspend fun fetchUser(id: String): String { delay(300); return "User:$id" }
suspend fun fetchPosts(id: String): List<String> { delay(500); return listOf("Post1") }
suspend fun fetchAvatar(id: String): ByteArray { delay(200); return ByteArray(1024) }
suspend fun processAvatar(data: ByteArray): ByteArray { delay(100); return data }
loadUserProfile फ़ंक्शन async के माध्यम से तीन समानांतर पृष्ठभूमि कार्य शुरू करता है। fetchUser और fetchPosts IO-बाउंड (नेटवर्क) हैं, Dispatchers.IO पर निष्पादित होते हैं। processAvatar CPU-बाउंड (इमेज प्रोसेसिंग) है, Dispatchers.Default पर निष्पादित होता है। await() सभी कार्य पूरा होने तक coroutine को निलंबित करता है। कुल निष्पादन समय तीन कार्यों के बीच अधिकतम समय (fetchPosts के लिए 500 ms) के बराबर है, उनके योग के नहीं। यह अनुक्रमिक निष्पादन पर coroutines का एक प्रमुख लाभ है।
Structured concurrency — एक सिद्धांत जहां प्रत्येक coroutine का एक पैरेंट स्कोप होता है, और पैरेंट को रद्द करने से चाइल्ड coroutines स्वचालित रूप से रद्द हो जाते हैं। Android में, lifecycleScope Activity नष्ट होने पर सभी coroutines को रद्द कर देता है। viewModelScope ViewModel साफ़ होने पर ऐसा करता है। यह पृष्ठभूमि कार्य लीक को रोकता है: यदि उपयोगकर्ता स्क्रीन बंद करता है, तो पृष्ठभूमि में रहते हुए coroutine उन डेटा को लोड करना जारी नहीं रखेगा जिनकी अब आवश्यकता नहीं है।
WorkManager — Android Jetpack लाइब्रेरी जो पृष्ठभूमि कार्यों को निष्पादित करने के लिए है जिन्हें डिवाइस रीस्टार्ट या ऐप बंद होने के बाद भी पूरा किया जाना चाहिए। Executors और coroutines के विपरीत, जो ऐप प्रक्रिया के भीतर रहते हैं, WorkManager कार्य को सिस्टम डिस्पैचर को सौंपता है जो उपयुक्त परिस्थितियों (नेटवर्क उपलब्धता, बैटरी चार्ज, खाली स्थान) के तहत निष्पादन की गारंटी देता है। WorkManager डेटा सिंक्रोनाइज़ेशन, लॉग अपलोड और बैकअप के लिए उपयुक्त है।
WorkManager में एक कार्य Worker (या coroutines के लिए CoroutineWorker) को एक्सटेंड करने वाला एक वर्ग है। Worker.doWork() WorkManager द्वारा प्रदान की गई पृष्ठभूमि थ्रेड पर निष्पादित होता है। परिणाम Result.success(), Result.retry() या Result.failure() के माध्यम से लौटाया जाता है। कार्यों को श्रृंखलाबद्ध किया जा सकता है: oneTimeWorkRequest.andThen(nextRequest).enqueue()। WorkManager बाधाओं (Constraints) को ध्यान में रखते हुए स्वयं इष्टतम निष्पादन समय चुनता है।
// Coroutines के साथ WorkManager
import android.content.Context
import androidx.work.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
class SyncWorker(
appContext: Context,
workerParams: WorkerParameters
) : CoroutineWorker(appContext, workerParams) {
override suspend fun doWork(): Result {
// Dispatchers.Default पर निष्पादित हो रहा है (डिफ़ॉल्ट रूप से)
return withContext(Dispatchers.IO) {
try {
syncDataToServer()
Result.success()
} catch (e: Exception) {
if (runAttemptCount < 3) Result.retry() else Result.failure()
}
}
}
private suspend fun syncDataToServer() {
// सिंक्रोनाइज़ेशन का अनुकरण
delay(1000)
}
}
// बाधाओं के साथ WorkManager कार्य शुरू करना
fun scheduleSync(context: Context) {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.build()
val syncWork = OneTimeWorkRequestBuilder<SyncWorker>()
.setConstraints(constraints)
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 10, java.util.concurrent.TimeUnit.SECONDS)
.build()
WorkManager.getInstance(context).enqueue(syncWork)
}
SyncWorker CoroutineWorker — Worker का एक संस्करण जो coroutines का समर्थन करता है, को एक्सटेंड करता है। doWork() Dispatchers.Default पर निष्पादित होता है, withContext के माध्यम से नेटवर्क संचालनों के लिए IO पर स्विच करता है। Constraints सुनिश्चित करते हैं कि सिंक्रोनाइज़ेशन केवल नेटवर्क उपलब्ध होने और बैटरी चार्ज निम्न स्तर से कम न होने पर ही शुरू हो। EXPONENTIAL के साथ BackoffCriteria पुनः प्रयासों के बीच अंतराल बढ़ाता है: 10, 20, 40 सेकंड।
नियमित कार्यों (हर 15 मिनट में सिंक्रोनाइज़ेशन, हर घंटे एनालिटिक्स भेजना) के लिए, WorkManager PeriodicWorkRequestBuilder प्रदान करता है। न्यूनतम अंतराल 15 मिनट है। OneTimeWorkRequest के विपरीत, PeriodicWorkRequest सटीक अंतराल पालन की गारंटी नहीं देता — सिस्टम बैटरी बचाने के लिए कई आवधिक कार्यों को समूहित कर सकता है। सटीक अंतराल के लिए, AlarmManager का उपयोग करें, लेकिन Android 12+ पर सटीक अलार्म पर प्रतिबंधों पर ध्यान दें।
पहली गलती — प्रत्येक कार्य के लिए नई Thread बनाना। new Thread().start() स्टैक के लिए ~1 MB आवंटित करते हुए एक नेटिव थ्रेड बनाता है। 100 समानांतर कार्यों के लिए, यह स्टैक के लिए 100 MB है, साथ ही कॉन्टेक्स्ट स्विच ओवरहेड भी। थ्रेड पूल का उपयोग करें: Executors.newFixedThreadPool(n) (Android) या DispatchQueue.global() (iOS) — वे थ्रेड्स का पुन: उपयोग करते हैं, ओवरहेड को कई गुना कम करते हैं।
दूसरी गलती — बिना सिंक्रोनाइज़ेशन के कई पृष्ठभूमि थ्रेड्स से mutable स्थिति तक पहुंचना। यदि दो पृष्ठभूमि थ्रेड एक साथ एक ही ArrayList या HashMap में लिखते हैं, तो race condition उत्पन्न होती हैं: Android में ConcurrentModificationException, iOS में डेटा भ्रष्टाचार। समाधान: थ्रेड-सुरक्षित कलेक्शन (ConcurrentHashMap, CopyOnWriteArrayList) का उपयोग करें या एकल कतार (DispatchQueue serial) के माध्यम से पहुंच को क्रमबद्ध करें।
तीसरी गलती — जीवनचक्र प्रबंधन के बिना पृष्ठभूमि कार्य। Activity या ViewModel के जीवनचक्र से बंधे बिना वैश्विक स्कोप में coroutine शुरू करना लीक की ओर ले जाता है: स्क्रीन नष्ट होने के बाद भी कार्य चलता रहता है। Android में, lifecycleScope (Activity/Fragment) या viewModelScope (ViewModel) का उपयोग करें। iOS में, क्लोज़र में weak self का उपयोग करें और deinit पर कार्यों को रद्द करें।
अक्सर पूछे जाने वाले प्रश्न
Background Thread — एक थ्रेड जिस पर UI से संबंधित न होने वाले कार्य निष्पादित किए जाते हैं: नेटवर्क अनुरोध, फ़ाइल पढ़ना/लिखना, JSON पार्सिंग, गणनाएं। यह Main Thread को भारी काम से मुक्त करता है, इंटरफ़ेस की प्रतिक्रियाशीलता बनाए रखता है। iOS में, पृष्ठभूमि थ्रेड्स GCD (DispatchQueue.global) के माध्यम से प्रबंधित किए जाते हैं; Android में, Executors या Kotlin Coroutines (Dispatchers.IO, Dispatchers.Default) के माध्यम से।
Dispatchers.IO ब्लॉकिंग I/O संचालनों के लिए डिज़ाइन किया गया है: फ़ाइलें पढ़ना, नेटवर्क अनुरोध, DB के साथ काम करना। इसका पूल 64 थ्रेड्स का है। Dispatchers.Default CPU-गहन कार्यों के लिए है: सॉर्टिंग, फ़िल्टरिंग, इमेज प्रोसेसिंग। इसका पूल CPU कोर की संख्या के बराबर है। I/O संचालनों के लिए Dispatchers.Default का उपयोग सभी कोर को ब्लॉक कर सकता है, और CPU कार्यों के लिए Dispatchers.IO का उपयोग अत्यधिक संख्या में थ्रेड्स बना सकता है।
DispatchQueue.global(qos: .background).async { } वैश्विक पृष्ठभूमि कतार पर एक ब्लॉक भेजता है। पृष्ठभूमि कार्य पूरा होने के बाद, UI अपडेट करने के लिए DispatchQueue.main.async { } के माध्यम से मुख्य थ्रेड पर वापस लौटना होगा। अनुक्रमिक पृष्ठभूमि कार्यों के लिए, maxConcurrentOperationCount = 1 के साथ OperationQueue या DispatchQueue(label: "serial") का उपयोग करें।
अनुशंसित पृष्ठभूमि थ्रेड्स की संख्या CPU कोर की संख्या और IO-बाउंड कार्यों के लिए 1 के बराबर है। आधुनिक 8-कोर डिवाइस पर, यह 9 थ्रेड्स है। सैकड़ों थ्रेड्स बनाने से thread starvation होती है: OS कार्यों को निष्पादित करने की तुलना में कॉन्टेक्स्ट स्विचिंग पर अधिक समय बिताता है। iOS में GCD और Android में Executors स्वचालित रूप से वर्तमान डिवाइस के लिए थ्रेड पूल को अनुकूलित करते हैं।
Kotlin Coroutines में, Main Thread पर वापसी स्वचालित रूप से होती है यदि coroutine Main स्कोप (lifecycleScope.launch, viewModelScope.launch) में शुरू किया गया था। withContext(Dispatchers.IO) फ़ंक्शन coroutine को IO थ्रेड पर निलंबित करता है, और पूरा होने के बाद स्वचालित रूप से उस डिस्पैचर पर फिर से शुरू करता है जहां इसे शुरू किया गया था (आमतौर पर Main)। DispatchQueue.main.async के स्पष्ट कॉल की आवश्यकता नहीं है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें