🍟

Asynchronous & Synchronous

に公開

聞き慣れない単語だが

Asynchronous & Synchronous聞き慣れない単語ですね。非同期処理のPromiseasync/awaitと同期処理なら知っている。海外の動画でiOSの学習をしていたときに出てきました。
実はこれ知ってる表現でした。

MDNに解説があったので読んでいただけるとご理解いただけると思います。

Asynchronous (非同期)

公式より引用

非同期 (asynchronous) という用語は、 2 つ以上のオブジェクトやイベントが同時に存在しない、または起こらない、すなわち同期していないことを表します。複数の関連のあることが、前回起こったことの完了に依存することなく起こるとき、それらは非同期です。

他の処理を待たずに実行することできる。趣味で作った本に書いていたTypeScriptのソースコードを例に出すとこんな感じですかね。

// Promiseを使ってhttps://jsonplaceholderからデータを非同期に取得する
function fetchUser(): Promise<void> {
  return new Promise((resolve, reject) => {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then((res) => res.json())
      .then((users) => {
        console.log(users);
        resolve(users);
      });
  });
}

fetchUser()
  .then((users) => {
    // データを取得した後の処理
    console.log(users);
  })
  .catch((err) => {
    // エラーが発生した場合の処理
    console.log(err);
  });

Promiseを短くかけるシンタックスシュガーのasync/awaitもある。よく使われるのはこっち。

// async/awaitを使ってhttps://jsonplaceholderからデータを非同期に取得する
async function AsyncUser(): Promise<void> {
  try {
    // 成功した場合の処理
    const res = await fetch("https://jsonplaceholder.typicode.com/users");
    const users = await res.json();
    console.log(users);
  } catch (err) {
    // エラーが発生した場合の処理
    console.log(err);
  }
}

AsyncUser();

iOSの場合だと別のアカウントで書いていた記事があったのですが、こちらですね。
https://zenn.dev/jboysan/articles/b806dc4405aa9e

import SwiftUI

// MARK: - Models

struct User: Codable, Identifiable {
    let id = UUID()
    let login: String
    let url: String
    let avatar_url: String
    let html_url: String
}

struct APIResponse: Codable {
    let items: [User]
}

// MARK: - ViewModel

enum FetchState {
    case idle
    case loading
    case loaded([User])
    case error(Error)
}

class UserViewModel: ObservableObject {
    @Published var fetchState: FetchState = .idle
    
    func getUsers() {
        fetchState = .loading
        
        Task {
            let result = await fetchUsers()
            DispatchQueue.main.async {
                switch result {
                case .success(let users):
                    self.fetchState = .loaded(users)
                case .failure(let error):
                    self.fetchState = .error(error)
                }
            }
        }
    }
    
    private func fetchUsers() async -> Result<[User], Error> {
        guard let apiURL = URL(string: "https://api.github.com/search/users?q=greg") else {
            return .failure(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"]))
        }
        
        do {
            let (data, _) = try await URLSession.shared.data(from: apiURL)
            let apiResponse = try JSONDecoder().decode(APIResponse.self, from: data)
            return .success(apiResponse.items)
        } catch {
            return .failure(error)
        }
    }
}

// MARK: - Views

struct LoadingView: View {
    var body: some View {
        VStack {
            ProgressView().padding()
            Text("Fetching Users...")
        }
    }
}

struct UserListView: View {
    let users: [User]
    
    var body: some View {
        List(users) { user in
            Link(destination: URL(string: user.html_url)!) {
                HStack {
                    AsyncImage(url: URL(string: user.avatar_url)) { phase in
                        switch phase {
                        case .success(let image):
                            image.resizable().frame(width: 50, height: 50)
                        default:
                            Image(systemName: "nosign")
                        }
                    }
                    VStack(alignment: .leading) {
                        Text(user.login)
                        Text(user.url)
                            .font(.system(size: 11))
                            .foregroundColor(Color.gray)
                    }
                }
            }
        }
    }
}

struct ContentView: View {
    @StateObject private var viewModel = UserViewModel()
    
    var body: some View {
        NavigationStack {
            Group {
                switch viewModel.fetchState {
                case .idle:
                    Text("Tap to load users")
                case .loading:
                    LoadingView()
                case .loaded(let users):
                    UserListView(users: users)
                case .error(let error):
                    Text("Error: \(error.localizedDescription)")
                }
            }
            .navigationTitle("GitHub Users")
        }
        .onAppear {
            viewModel.getUsers()
        }
    }
}

#Preview {
    ContentView()
}

少し前に書いたGitHubサーチするコードですがまだ動きます。参考までに試してみてください。

Synchronous (同期通信方式)

公式より引用

同期 (Synchronous) とは、各当事者がメッセージを瞬時に(または可能な限り直ちに)受信(また必要な場合には処理および返信)するリアルタイムのコミュニケーションのことを指します。

人間での例としては電話が挙げられます。電話の通話中は、あなたは通話相手に直ちに返事をしやすいです。

プログラミングのコマンドの多くも同期的です。例えば、計算式を入力すると、環境は即座にその結果を返します(そうならないようにプログラムをしない限り)。

よくあるコードが同期処理と呼ばれているものですね。他の処理が実行されるのを待ってい実行されるという表現を聞きますね。

SwiftのforEachをコードでロジックを解説すると。。。
「forEach は同期的に動作します。各要素に対するクロージャは、前の処理が終わってから次の処理が順番に実行されるため、常に順番通りに出力がされます。」

var arr: [Int] = [1, 2, 3, 4, 5]

arr.forEach({
    if $0 == 5 {
        print("要素数は同じ5です")
    } else {
        print("要素数は \($0)")
    }
})

まとめ

海外の記事や動画を見たときに、Asynchronousというテキストが出てきたら非同期書、Synchronousというテキストが出てきたら同期処理と理解できるようになりました。

普段日本語で見てるもので英語だとこんな表現使うんですね。普段から専門用を英語で使うようにすると少しずつ外国の人のテキストの内容が理解できるようになりそう。

Discussion