Concurrency Programming Guide - 1

Concurrency Programming Guide - 2


Concurrency Programming Guide - 3


Factor Out Executable Units of Work

  • 앱의 task를 이해했다면, 코드가 동시성의 이점을 얻을 수 있는 “위치”를 식별할 수 있어야 한다.

  • task에서 하나 이상의 단계의 순서를 변경하면, 결과가 변경되므로 해당 단계를 연속적으로 수행해야한다.

  • 순서를 변경해도 결과에 영향을 미치지 않으면, 해당 단계를 동시에 수행하는 것을 고려해야한다.

    • 두 경우 모두 수행 할 단계를 나타내는 실행 가능 작업단위를 정의한다.

    • 그 다음 작업단위가 블록 또는 operation객체를 사용하여 캡슐화 된 후 해당 큐에 디스패치 된다

      • dispatch (명사) : 급파, (동사) : 급파하다, 특파하다
  • 식별한 각 작업의 실행 단위마다 실행되는 “작업량”에 관해서는 적어도 초기에는 걱정하지 않아도 된다.

  • 쓰레드를 회전시키는데에 항상 비용이 들지만, dispatch queues 및 operation queues경우, 이러한 비용이 기존 쓰레드보다 훨씬 적다.

    • 따라서 쓰레드를 사용 할 수 있는 것보다 더 작은 작업단위를 큐를 사용하여 보다 효율적으로 실행 할 수 있다.
  • 물론 실제 성능을 측정하고, 필요에 따라 task 크기를 조정해야하지만, 처음에는 task를 너무 작게 간주해서는 안된다.


Identify the Queues You Need

  • task가 개별 작업단위로 나누어져 블록객체 또는 Operation객체를 사용하여 캡슐화되었으므로. 해당 코드를 실행하는데 사용할 큐를 정의해야한다.

  • 주어진 task의 경우, task를 올바르게 수행하려면 생성한 블록이나 Operation객체와 해당 task를 실행해야하는 순서를 검토해야한다.

  • 블록을 사용하여 task를 구현한 경우, 블록은 Serial 또는 c dispatch queue에 추가 할 수 있다.

  • 특정 순서가 필요한 경우, 블록을 Serial dispatch queue에 항상 추가한다.

  • 특정 순서가 필요하지 않은 경우, 블록을 Concurrent dispatch queue에 추가하거나 필요에 따라 여러개의 다른 dispatch queue에 추가 할 수 있다

  • Operation 객체를 사용하여 task를 구현한 경우, 큐를 선택하는 것이 객체 구성보다 덜 흥미로운 경우가 많다.

  • Serial 로 Operation 객체를 수행하려면, 관련 객체간의 종속성을 구성해야한다.

  • 종속성은 종속된 객체가 작업을 완료할 때 까지 하나의 Operation이 실행되지 못하도록 한다.


Tip for Improving Efficiency

  • 작은 task로 코드를 추가하고, 큐에 추가하는 것 이외에도 큐를 사용하여 코드의 전체 효율성을 향상 시킬 수 있는 방법이 있다

    • (1) 메모리 사용량이 중요한 경우, task내에서 직접 값을 계산하는 것을 고려

      • 앱이 이미 메모리 바운드이면 계산값(compution values)는 main memory에서 캐시돤 값을 로드하는 것 보다 더 빠를 수도 있다

        • 직접 계산하는 것이 메인 메모리에서 로드하는 것보다 더 빠를 수 있다
      • 계산값은 지정된 프로세서 코어의 레지스터 및 캐시를 직접 사용하며 이는 main memory보다 훨씬 빠르다.

      • 물론 테스트에서 직접 계산하는것이 성능에서 더 우위에 있다는 것을 나타냈을 때만 이를 수행해야 한다

    • (2) Serical task를 조기에 식별하고, 동시 작업을 보다 효율적으로 수행 할 수 있도록 해야한다.

      • 일부 공유 리소스를 사용하기 때문에, 작업을 연속적으로 실행해야하는 경우, 해당 공유 리소스를 제거하기 위해 아키텍쳐를 변경하는것이 좋다.

      • 리소스를 필요로 하거나 리소스를 모두 제거하는 각 클라이언트에 대해 리소스의 복사본을 만드는 것을 고려할 수 있다.

    • (3) lock을 사용 금지.

      • dispatch queues 및 operation queues에 의해 제공되는 자원은 대부분의 상황에서 lock을 불필요하게 만든다

      • 일부 공유 자원을 보호하기 위해 lock을 사용하는 대신, Serial 큐를 지정(또는 operation 오브젝트 종속성을 사용하여) 올바른 순서로 task를 실행

    • (4) 가능할 때마다 시스템 프레임워크에 의존

      • 동시성을 얻는 가장 좋은 방법은 시스템 프레임워크가 제공하는 내장된 동시성을 이용하는것이다.

      • task를 정의 할 때, 기존 프레임워크가 원하는 것과 정확하게 동시에 수행하는 함수 또는 메소드를 정의하는지 확인해야한다.

      • API를 사용하면 노력을 줄일 수 있으며, 가능한 최대의 동시성을 제공할 가능성이 크다.


Performance Implications

  • Operation queues, dispatch queues 및 dispatch sources는 더 많은 코드를 동시에 더 쉽게 실행 할 수 있도록 제공된다.

    • 그러나 이러한 기술이 앱의 효율성이나 응답성(Response)을 향상시키는 것은 아니다

    • 필요에 따라 효과적이며 앱의 다른 리소스에 과도한 부담을 주지 않는 방식으로 큐를 사용해야하며 그 책임은 개발자에게 있다

      • 예를들어, 10000개의 operation 객체를 만들어, operation queue에 전송할 수는 있지만, 앱에서 중요한 메모리를 할당 할 수 있으므로 페이징 및 성능저하가 발생할 수 있다.
  • 큐나 쓰레드를 사용하여 코드에 동시성을 도입하기 전에, 항상 앱의 현재 성능을 반영하는 일련의 기준 지표 혹은 기준 측정 항목(baseline metrics)을 수집해야한다.

  • 변경사항을 도입한 후에는 추가 측정 항목을 수집하고 이것을 기준 지표와 비교하여 앱의 전반적인 효율성이 향상되었는지 확인해야 한다.

  • 동시성 도입으로 인해 앱의 효율성이 떨어지거나 응답성이 떨어지면 가능한 performance tool을 이용하여 잠재적인 원인을 확인해야한다.


Concurrency and other Technologies

  • 코드를 모듈화 된 task로 분해하는 것이 앱의 동시성을 향상시키는 가장 좋은 방법이다.

    • 그러나 이 설계 방법은 모든 경우의 모든 앱의 요구를 만족시키지 못할 수 있다.
  • task에 따라 앱의 전체 동시성을 추가로 향상시킬수 있는 다른 옵션이 있을 수 있다.


OpenCL and Concurrency

  • OS X에서 OpenCL(Open Computing Language)은 컴퓨터 그래픽 프로세서에 일반적인 계산을 수행하기 위한 표준 기반 기술이다

  • OpenCL은 커다란 데이터 집합에 적용 할 수 있도록 잘 정의 된 계산 집합이 있는 경우, 사용 할 수 있는 좋은 기술.

    • 예를들어, OpenCL을 사용하여 이미지 픽셀에 대한 필터 계산을 수행하거나 이미지의 픽셀계산을 사용하여 여러 값에 대한 복잡한 계산을 한번에 수행 할 수 있다.

    • 바꾸어 말하면, OpenCL은 데이터를 병렬로 조작 할 수 있는 문제 Set에 집중되어 있다.

  • OpenCL은 대용향 데이터의 병렬 연산을 수행하는데 적합하지만, 보다 일반적인 목저의 계산에는 적합하지 않다.

  • 데이터와 필요한 작업 커널(work kernel)을 GPU에서 작동 할 수 있도록 그래픽 카드로 준비하고 전송하는데 노력은 중요하지 않다.

  • 마찬가지로, OpenCL에 의해 생성된 결과를 검색하는데 필요한 노력이 필요하지 않다

  • 결과적으로 시스템과 상호작용하는 모든 작업은 일반적으로 OpenCL과 함께 사용하지 않는 것이 좋다

    • 예를들어, OpenCL을 사용하여 파일이나 네트워크 스트림의 데이터를 처리하지 말아야한다.
  • OpenCL을 사용하여 수행하는 작업은 그래픽 프로세서로 전송되고 독립적으로 계산될 수 있도록 훨씬 더 독립적이어야 한다.


참고자료