Swift, Concurrency


Concurrency(同期)


同期プログラミングとも呼ばれます.Concurrencyはタスク別の携帯電話で、私たちが使っているiphoneは歌を再生するだけでなく、ユーザーの入力に基づいて電子メールを書くことができ、途中で電話に出ることもできます.これは同期性です.
歌を再生するときに画面に触れたり、インターネットで検索したりできないと不便です.
コードが実際にどうなるか見てみましょう.
//1
func calculatePrimes() {
    for number in 0...1_000_000 {
      let isPrimeNumber = isPrime(number: number)
      print("\(number) is prime: \(isPrimeNumber)")
    }
  }
  
//2
func isPrime(number: Int) -> Bool {
    if number <= 1 {
      return false
    }
    if number <= 3 {
      return true
    }
    
    var i = 2
    while i * i <= number {
      if number % i == 0 {
        return false
      }
      i = i + 2
    }
    return true
 }
calculatePrimes()は1万から100万の自然水の中から少数を求める方法で、やったことがある人は知っているはずですが、これは長い時間がかかる仕事です.
var body: some View {
    VStack {
      Spacer()
      DatePicker(selection: .constant(Date())) {
        Text("Date")
      }
      .datePickerStyle(.wheel)
      .labelsHidden()
      Button {
        calculatePrimes()
      } label: {
        Text("Calculate Primes")
      }
      Spacer()
 }
画面にはDataPicker UIがあり、ボタンを押して小数点を求める.

小数点を求めるボタンをクリックすると、DatePickerのUIは計算を停止します.
これは、DatePickerのユーザインタラクションおよびcalculatePrimes()がプライマリスレッド上で実行されるためである.calculatePrimes()はスレッドを占有しており、他のプライマリスレッド上で動作する必要があるユーザのインタラクションは機能しない.

Thread/Multithread


私は何度も多機能Threadを聞いたことがありますが、Threadは何ですか?
計算では、スレッドはオペレーティングシステムスケジューラによって独立に管理されるプログラマブルコマンドの最小シーケンスである。
CPUは、複数のカーネルとより多くのスレッドを持ち、物理的なタスクを同時に処理できるようになりました.これがマルチスレッドです.
この部分はParallelismと区別されています.並列プログラミングと呼ばれるParallelismは、スレッドではなくCPUである.従来のcaculatePrimes()法は、1つのスレッドで計算されるのではなく、分割計算によって動作速度を速める.Parallelismのコアはスレッドです.

Context Swiching

Concurrencyのもう1つのコアはContext Switchであり、1つのコアはTimeSlicingと呼ばれる方法で同時動作する.簡単に理解すると、私がコーヒーを作るのは、このコーヒーを作る動作の中で、コーヒー豆を粉砕したり、水を沸かしたり、コップを用意したりする動作で、速くできていて、他の人(ユーザー)の立場から見ると、ほとんど同時に発生しています.

Use Concurrency


だから最初のアプリケーションに戻って、iOSは基本的にマルチスレッドです.もちろん、UIタスクは、少数の取得と同時に処理することができる.しかし実際には計算のためUIが使えなかった.別のスレッドで素数を求める操作を行うことを明記する必要があります.
りんごに感謝?Threedを使いやすいフレームワークを提供します.非常に低い角度から見ると、NSThreadとさらに下に進み、Unix POSIX ThreadでこのThreadを使用することができますが、Grand Central Dispatch(GCD)があります.GCDもConcurrency操作用のフレームワークであり、かなり低いレベルに設計されている.
もう1つのオプションは、GCD上に構築され、より簡単で簡潔なコードを提供するOpen Queueです.
次に2019年に発売されたCombineは、バックグラウンドで作業を宣言型に管理している.オペレータによってスレッド間を簡単に切り替えることができます.
まだあります.次はSWIFT Concurrencyです.

GCD


GCDはスレッド上に構築され,共有スレッドプールを管理する.これを使用してDispatchQueueでコードブロックを処理し、GCDはそのコードを実行するスレッドを決定します.

Queue


QueueはFIFO構造であり,先に進んだ作業を先に導き出すのが特徴である.GCDは同様に動作順序を保証する.このときQueueはSeiralまたはConcurrentであってもよい

これにより、シリアルは線形時間内に1つのタスクのみを実行します.Task 1が終了するとTask 2が実行されます.Threedを使用して一貫性を保つことができます.

ConcurrentはTaskの順にタスクを割り当てていますが、シリアルとは異なりTask 3とTask 4よりもTask 2の方が早く完了するため、戻ってくるタスクの方が早くなります.だから作業手順は保証できません.
コーヒーを炒めてコップに入れて水を入れて、水を先に沸かして、先に水を捨てます

Operation Queue


GCDを使用するために、Openionを継承して作成することができます.
class CaculatePrimeOperation: Operation {
  
  
  override func main() {
    
    for number in 0...1_000_000 {
      let isPrimeNumber = isPrime(number: number)
      print("\(number) is prime: \(isPrimeNumber)")
    }
  }
  
  func isPrime(number: Int) -> Bool {
    if number <= 1 {
      return false
    }
    if number <= 3 {
      return true
    }
    
    var i = 2
    while i * i <= number {
      if number % i == 0 {
        return false
      }
      i = i + 2
    }
    return true
  }
  
}
Concurrencyは、前に記述した小数点を求める方法を移植する.
let operation = CaculatePrimeOperation()
func calculatePrimes() {
  
  let queue = OperationQueue()
  queue.addOperation(operation)

}
クラスのインスタンスが作成され、OpenQueueインスタンスmain()に渡される.
  func calculatePrimes() {
    let operation = CalculatePrimeOperation()
    let queue = OperationQueue()
    queue.addOperation(operation)
  }
実際には、Openを継承するクラスを作成する必要はありません.addOpenは閉パッケージを提供するので、メソッドをその閉パッケージに書き込むだけです.addOperationは、インスタンスの作成時に残りのスレッドを自動的に割り当てます.プライマリ・スレッドの使用を明確に要求した場合
let mainQueue = OpearationQueue.main
使用可能OperationQueueに加えて、より簡単な方法があります.

DispatchQueue

DispatchQueue.global(qos: .userInitiated).async {
  for number in 0...1_000_000 {
    let isPrimeNumber = number.isPrime
    print("\(number) is prime: \(isPrimeNumber)")
  }
}
ThreedをGlobalに送ることができます.qos設定はアップルのドキュメントで詳細に表示できます.
https://developer.apple.com/documentation/dispatch/dispatchqos/qosclass
したがって,以前は小数を求めるために反応しなかったUIを構築できるようになった.

Swift Concurrency


SWIFT Concurrencyを使用してこの操作を実行するには1行のコードが必要ですか?増えることができます.
  func calculatePrimes() {
    doneLabel = "Calculating!"
    Task {
      for number in 0...1_000_000 {
        let isPrimeNumber = number.isPrime
        print("\(number) is prime: \(isPrimeNumber)")
      }
    }
    doneLabel = "Done!"
  }
Refereces
  • raywenderlich Grand Cental Dispatch Tutorial for Swift4 by Evan Dekhayser
  • Swift Apprentice
  • Monocoding