{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "6b7abc7b-b435-43d1-9fd8-c349ee8710f3",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"Qiskit Serverless 의 컴퓨팅 및 데이터 리소스 관리\"\n",
        "description: \"Qiskit Serverless 를 통해 Qiskit 패턴 전반에 걸쳐 컴퓨팅 및 데이터를 관리하세요.\"\n",
        "---\n",
        "\n",
        "<span id=\"manage-qiskit-serverless-compute-and-data-resources\" />\n",
        "\n",
        "# Qiskit Serverless 의 컴퓨팅 및 데이터 리소스 관리\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "3b0771d6-95c9-46dc-955a-f8702f6a2632",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "<Accordion>\n",
        "  <AccordionItem title=\"패키지 버전\">\n",
        "    이 페이지의 코드는 다음 요구 사항을 사용하여 개발되었습니다.\n",
        "    다음 버전 이상을 사용하는 것이 좋습니다.\n",
        "\n",
        "    ```\n",
        "    qiskit[all]~=2.0.0\n",
        "    qiskit-ibm-runtime~=0.37.0\n",
        "    qiskit-serverless~=0.27.0\n",
        "    ```\n",
        "  </AccordionItem>\n",
        "</Accordion>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "95b2f280-f685-455f-83e9-b172445d7c6a",
      "metadata": {},
      "source": [
        "<Admonition type=\"tip\">\n",
        "  **Qiskit Serverless 업그레이드를 진행 중이며, 기능이 빠르게 변화하고 있습니다.** 이 개발 단계 동안, 릴리스 노트와 최신 문서는 [Qiskit ServerlessGitHub](https://qiskit.github.io/qiskit-serverless/index.html) 페이지에서 확인하실 수 있습니다.\n",
        "</Admonition>\n",
        "\n",
        "키스킷 서버리스를 사용하면 CPU, QPU 및 기타 컴퓨팅 가속기를 포함하여 [키스킷 패턴](/docs/guides/intro-to-patterns) 전반에서 컴퓨팅과 데이터를 관리할 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "380354c0-5cab-464d-b10f-c94055de3605",
      "metadata": {},
      "source": [
        "<span id=\"set-detailed-statuses\" />\n",
        "\n",
        "## 상세 상태 설정\n",
        "\n",
        "서버리스 워크로드는 워크플로 전반에 걸쳐 여러 단계로 구성됩니다. 기본적으로 `job.status()` 에서 볼 수 있는 상태는 다음과 같습니다:\n",
        "\n",
        "* \\*\\*`QUEUED`\\*\\*워크로드가 기존 리소스에 대해 대기열에 대기 중입니다\n",
        "* \\*\\*`INITIALIZING`\\*\\*워크로드가 설정되었습니다\n",
        "* \\*\\*`RUNNING`\\*\\*워크로드가 현재 클래식 리소스에서 실행 중입니다\n",
        "* \\*\\*`DONE`\\*\\*워크로드가 성공적으로 완료되었습니다\n",
        "\n",
        "다음과 같이 특정 워크플로 단계를 추가로 설명하는 사용자 지정 상태를 설정할 수도 있습니다.\n",
        "\n",
        "<Admonition type=\"caution\">\n",
        "  노트북에서 코드 셀을 로컬로 실행하면 [매직 ](https://ipython.readthedocs.io/en/stable/interactive/magics.html#cellmagic-writefile)`%%writefile` 명령어가 표시됩니다. 이 마법 같은 명령어를 사용하여 셀을 실행하면, 셀이 실제로 실행되는 대신 디스크에 저장됩니다.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a69df8bc-5033-45bf-a837-cffa9d29b844",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Writing ./source_files/status_example.py\n"
          ]
        }
      ],
      "source": [
        "%%writefile ./source_files/status_example.py\n",
        "\n",
        "# If you include the preceding `%%writefile` command (visible only when you read this locally in a\n",
        "# notebook), running this cell saves to disk rather than executing the code.\n",
        "\n",
        "from qiskit_serverless import update_status, Job\n",
        "\n",
        "# # If your function has a mapping stage, particularly application functions, you can set the status\n",
        "# to \"RUNNING: MAPPING\" as follows:\n",
        "update_status(Job.MAPPING)\n",
        "\n",
        "# # While handling transpilation, error suppression, and so forth, you can set the status to\n",
        "# \"RUNNING: OPTIMIZING_FOR_HARDWARE\":\n",
        "update_status(Job.OPTIMIZING_HARDWARE)\n",
        "\n",
        "# # After you submit jobs to IBM Quantum Compute Service, the underlying quantum job will be queued. You can set\n",
        "# status to \"RUNNING: WAITING_FOR_QPU\":\n",
        "update_status(Job.WAITING_QPU)\n",
        "\n",
        "# # When the Quantum Compute job starts running on the QPU, set the following status\n",
        "# \"RUNNING: EXECUTING_QPU\":\n",
        "update_status(Job.EXECUTING_QPU)\n",
        "\n",
        "## Once QPU is completed and post-processing has begun, set the status \"RUNNING: POST_PROCESSING\":\n",
        "update_status(Job.POST_PROCESSING)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a8746eae-6f15-4faf-8771-0f3062efc723",
      "metadata": {},
      "source": [
        "이 워크로드가 성공적으로 완료되면( `save_result()`)이 상태는 자동으로 `DONE` 으로 업데이트됩니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b2d40a63-3359-46e9-8f1b-4746b449b407",
      "metadata": {},
      "source": [
        "<span id=\"parallel-workflows\" />\n",
        "\n",
        "## 병렬 워크플로\n",
        "\n",
        "병렬 처리가 가능한 일반적인 작업의 경우, `@distribute_task` 데코레이터를 사용하여 작업 수행에 필요한 컴퓨팅 요구 사항을 정의하십시오. 먼저 [‘첫 번째 Qiskit Serverless 프로그램](/docs/guides/serverless-first-program) 작성하기’ 주제에 나온 예제를 `transpile_remote.py` 떠올려 보세요. 다음 코드를 참고하세요.\n",
        "\n",
        "다음 코드를 사용하려면 미리 [인증 정보를 저장해](/docs/guides/cloud-setup) 두어야 합니다. 해당 예시와 마찬가지로, 이 코드는 런타임 서비스를 생성하여, 이 서비스가 시작하는 모든 Qiskit Runtime 작업 및 세션이 상위 Qiskit Serverless 작업에 대해 추적되도록 합니다 `get_runtime_service()` . 자세한 내용은 [‘첫 번째 Qiskit Serverless 프로그램 작성하기](/docs/guides/serverless-first-program) ’를 참조하세요.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "475d82f0-15cc-4db3-b3b0-54b07822b2a0",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Writing ./source_files/transpile_remote.py\n"
          ]
        }
      ],
      "source": [
        "%%writefile ./source_files/transpile_remote.py\n",
        "\n",
        "# If you include the preceding `%%writefile` command (visible only when you read this locally in a\n",
        "# notebook), running this cell saves to disk rather than executing the code.\n",
        "\n",
        "from qiskit.transpiler import generate_preset_pass_manager\n",
        "from qiskit_serverless import distribute_task, get_runtime_service\n",
        "\n",
        "service = get_runtime_service()\n",
        "\n",
        "@distribute_task(target={\"cpu\": 1})\n",
        "def transpile_remote(circuit, optimization_level, backend):\n",
        "    \"\"\"\n",
        "    Transpiles an abstract circuit (or list of circuits)\n",
        "    into an ISA circuit for a given backend.\n",
        "    \"\"\"\n",
        "    pass_manager = generate_preset_pass_manager(\n",
        "        optimization_level=optimization_level,\n",
        "        backend=service.backend(backend)\n",
        "    )\n",
        "    isa_circuit = pass_manager.run(circuit)\n",
        "    return isa_circuit"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a5914f1d-f898-4db4-8d1e-ccc8081883b9",
      "metadata": {},
      "source": [
        "이 예제에서는 `transpile_remote()` 함수를 `@distribute_task(target={\"cpu\": 1})` 으로 꾸몄습니다. 실행하면 단일 CPU 코어로 비동기 병렬 워커 작업을 생성하고 워커를 추적하기 위한 참조와 함께 반환합니다. 결과를 가져오려면 `get()` 함수에 참조를 전달합니다. 이를 사용하여 여러 병렬 작업을 실행할 수 있습니다:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "e8fd31e6-9ab9-4d75-9ef9-a2b9ff9ad37a",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Appending to ./source_files/transpile_remote.py\n"
          ]
        }
      ],
      "source": [
        "%%writefile --append ./source_files/transpile_remote.py\n",
        "\n",
        "# If you include the preceding `%%writefile` command\n",
        "# (visible only when you read this locally in a\n",
        "# notebook), running this cell saves to disk rather than\n",
        "# executing the code.\n",
        "\n",
        "from time import time\n",
        "from qiskit_serverless import get, get_arguments, save_result, update_status, Job\n",
        "\n",
        "# Get arguments\n",
        "arguments = get_arguments()\n",
        "circuit = arguments.get(\"circuit\")\n",
        "optimization_level = arguments.get(\"optimization_level\")\n",
        "backend = arguments.get(\"backend\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "74fdcd4a-01cd-46ca-aa24-2a8a3605346f",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Appending to ./source_files/transpile_remote.py\n"
          ]
        }
      ],
      "source": [
        "%%writefile --append ./source_files/transpile_remote.py\n",
        "# If you include the preceding `%%writefile` command\n",
        "# (visible only when you read this locally in a\n",
        "# notebook), running this cell saves to disk rather than executing the code.\n",
        "\n",
        "# Start distributed transpilation\n",
        "update_status(Job.OPTIMIZING_HARDWARE)\n",
        "\n",
        "start_time = time()\n",
        "transpile_worker_references = [\n",
        "    transpile_remote(circuit, optimization_level, backend)\n",
        "    for circuit in arguments.get(\"circuit_list\")\n",
        "]\n",
        "\n",
        "transpiled_circuits = get(transpile_worker_references)\n",
        "end_time = time()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "81696ede-3aa5-4e8c-9d35-fdd70c1bf4db",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Appending to ./source_files/transpile_remote.py\n"
          ]
        }
      ],
      "source": [
        "%%writefile --append ./source_files/transpile_remote.py\n",
        "# If you include the preceding `%%writefile` command\n",
        "# (visible only when you read this locally in a\n",
        "# notebook), running this cell saves to disk rather than executing the code.\n",
        "\n",
        "# Save result, with metadata\n",
        "result = {\n",
        "    \"circuits\": transpiled_circuits,\n",
        "    \"metadata\": {\n",
        "        \"resource_usage\": {\n",
        "            \"RUNNING: OPTIMIZING_FOR_HARDWARE\": {\n",
        "                \"CPU_TIME\": end_time - start_time,\n",
        "                \"QPU_TIME\": 0,\n",
        "            },\n",
        "        }\n",
        "    },\n",
        "}\n",
        "\n",
        "save_result(result)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "611fe030-4494-46b5-9ea1-9678ac513210",
      "metadata": {},
      "source": [
        "<span id=\"explore-different-task-configurations\" />\n",
        "\n",
        "### 다양한 작업 구성을 탐색하세요\n",
        "\n",
        "`@distribute_task()` 을 통해 작업에 필요한 CPU, GPU, 메모리를 유연하게 할당할 수 있습니다. IBM 퀀텀® 플랫폼의 키스킷 서버리스의 경우, 각 프로그램에는 필요에 따라 동적으로 할당할 수 있는 16개의 CPU 코어와 32GB RAM이 장착되어 있습니다.\n",
        "\n",
        "CPU 코어는 다음과 같이 전체 CPU 코어 또는 부분 할당으로 할당할 수 있습니다.\n",
        "\n",
        "메모리는 바이트 단위로 할당됩니다. 1킬로바이트에는 1024바이트, 1메가바이트에는 1024킬로바이트, 1기가바이트에는 1024메가바이트가 있다는 것을 기억하세요. 작업자에게 2GB의 메모리를 할당하려면 `\"mem\": 2 * 1024 * 1024 * 1024` 을 할당해야 합니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "cea90969-cfbf-4181-9ffa-524f3709dc69",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Appending to ./source_files/transpile_remote.py\n"
          ]
        }
      ],
      "source": [
        "%%writefile --append ./source_files/transpile_remote.py\n",
        "# If you include the preceding `%%writefile` command\n",
        "# (visible only when you read this locally in a\n",
        "# notebook), running this cell saves to disk rather than executing the code.\n",
        "\n",
        "@distribute_task(target={\n",
        "    \"cpu\": 16,\n",
        "    \"mem\": 2 * 1024 * 1024 * 1024\n",
        "})\n",
        "def transpile_remote(circuit, optimization_level, backend):\n",
        "    return None"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6bc45489-56d0-4f46-8659-9df4d1555516",
      "metadata": {},
      "source": [
        "<span id=\"manage-data-across-your-program\" />\n",
        "\n",
        "## 프로그램 전반에 걸쳐 데이터를 관리하세요\n",
        "\n",
        "키스킷 서버리스를 사용하면 모든 프로그램에서 `/data` 디렉토리에 있는 파일을 관리할 수 있습니다. 여기에는 몇 가지 제한 사항이 포함됩니다:\n",
        "\n",
        "* 현재 `tar` 및 `h5` 파일만 지원됩니다\n",
        "* 이것은 플랫 `/data` 저장소일 뿐이며 `/data/folder/` 하위 디렉토리를 가질 수 없습니다\n",
        "\n",
        "다음은 파일을 업로드하는 방법을 보여줍니다. IBM Quantum 계정으로 Qiskit Serverless 에 인증되었는지 반드시 확인하십시오(자세한 지침은 [Qiskit Serverless 에 업로드하기를](/docs/guides/serverless-first-program#upload-to-qiskit-serverless) 참조하십시오).\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "0183278f-8ce3-4466-9255-097b2d211052",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "'{\"message\":\"/usr/src/app/media/5e1f442128cdf60018496a04/transpile_demo.tar\"}'"
            ]
          },
          "execution_count": 10,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import tarfile\n",
        "from qiskit_serverless import IBMServerlessClient\n",
        "\n",
        "# Create a tar\n",
        "filename = \"transpile_demo.tar\"\n",
        "file = tarfile.open(filename, \"w\")\n",
        "file.add(\"./source_files/transpile_remote.py\")\n",
        "file.close()\n",
        "\n",
        "# Get a reference to a QiskitFunction\n",
        "serverless = IBMServerlessClient()\n",
        "transpile_remote_demo = next(\n",
        "    program\n",
        "    for program in serverless.list()\n",
        "    if program.title == \"transpile_remote_serverless\"\n",
        ")\n",
        "\n",
        "# Upload the tar to Serverless data directory\n",
        "serverless.file_upload(file=filename, function=transpile_remote_demo)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4f762470-945f-48d5-a65b-c60d3b2dae3f",
      "metadata": {},
      "source": [
        "다음으로 `data` 디렉터리에 있는 모든 파일을 나열할 수 있습니다. 이 데이터는 모든 프로그램에서 액세스할 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "id": "14241fc4-d0cb-4803-8752-a460e1f48708",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/plain": [
              "['classifier_name.pkl.tar', 'output.json.tar', 'transpile_demo.tar']"
            ]
          },
          "execution_count": 11,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "serverless.files(function=transpile_remote_demo)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a97bd83e-8250-43bb-b1c4-d40d822c7ba2",
      "metadata": {},
      "source": [
        "프로그램에서 `file_download()` 을 사용하여 파일을 프로그램 환경으로 다운로드하고 `tar` 의 압축을 풀면 됩니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "ef649b2a-ed95-4dd2-89d9-61438faa7c1e",
      "metadata": {},
      "outputs": [],
      "source": [
        "%%writefile ./source_files/extract_tarfile.py\n",
        "# If you include the preceding `%%writefile` command\n",
        "# (visible only when you read this locally in a\n",
        "# notebook), running this cell saves to disk rather than executing the code.\n",
        "\n",
        "import tarfile\n",
        "from qiskit_serverless import IBMServerlessClient\n",
        "\n",
        "# For `token`, use the 44-character API_KEY you created\n",
        "# and saved from the IBM Quantum Platform Home dashboard\n",
        "serverless = IBMServerlessClient(token=\"<YOUR_API_KEY>\")\n",
        "files = serverless.files()\n",
        "demo_file = files[0]\n",
        "downloaded_tar = serverless.file_download(demo_file)\n",
        "\n",
        "\n",
        "with tarfile.open(downloaded_tar, 'r') as tar:\n",
        "    tar.extractall()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5b93dbdb-2060-468b-8496-ba98142a780b",
      "metadata": {},
      "source": [
        "이 시점에서 프로그램은 로컬 실험처럼 파일과 상호 작용할 수 있습니다. `file_upload()` , `file_download()`, `file_delete()` 을 로컬 실험 또는 업로드한 프로그램에서 호출하여 일관되고 유연한 데이터 관리를 할 수 있습니다.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a004dd78-0e0a-4a3b-83cb-333469533ef6",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## 다음 단계\n",
        "\n",
        "<Admonition type=\"info\" title=\"권장사항\">\n",
        "  * [기존 코드를 Qiskit Serverless 로 이식한](/docs/guides/serverless-port-code) 전체 예제를 확인해 보세요.\n",
        "  * 연구자들이 [양자 화학을 탐구하기](https://arxiv.org/abs/2405.05068v1) 위해 키스킷 서버리스 및 양자 중심 슈퍼컴퓨팅을 사용한 논문을 읽어보세요.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}