<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>SSAMKO의 개발 이야기</title>
    <link>https://ssamko.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 5 Aug 2026 13:28:56 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>SSAMKO</managingEditor>
    <image>
      <title>SSAMKO의 개발 이야기</title>
      <url>https://tistory1.daumcdn.net/tistory/3797620/attach/80058d32116248b89bb2c7d2736f3880</url>
      <link>https://ssamko.tistory.com</link>
    </image>
    <item>
      <title>[ansible] 가상환경 설정. source 를 찾을 수 없다는 에러. &amp;quot;stderr&amp;quot;: &amp;quot;/bin/sh: 1: source: not found&amp;quot;</title>
      <link>https://ssamko.tistory.com/77</link>
      <description>&lt;h1&gt;Ansible&lt;/h1&gt;
&lt;p&gt;ansible로 가상환경을 설정해 그 안에서 작업하려고 &lt;code&gt;source&lt;/code&gt; 커맨드를 사용하면 아래와 같은 에러를 마주치게 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;fatal: [default]: FAILED! =&amp;gt; {&amp;quot;changed&amp;quot;: true, &amp;quot;cmd&amp;quot;: &amp;quot;source /home/ubuntu/venv/bin/activate &amp;amp;&amp;amp; pip install -r /home/ubuntu/requirements.txt&amp;quot;, &amp;quot;delta&amp;quot;: &amp;quot;0:00:00.003097&amp;quot;, &amp;quot;end&amp;quot;: &amp;quot;2021-12-01 05:22:18.087230&amp;quot;, &amp;quot;msg&amp;quot;: &amp;quot;non-zero return code&amp;quot;, &amp;quot;rc&amp;quot;: 127, &amp;quot;start&amp;quot;: &amp;quot;2021-12-01 05:22:18.084133&amp;quot;, &amp;quot;stderr&amp;quot;: &amp;quot;/bin/sh: 1: source: not found&amp;quot;, &amp;quot;stderr_lines&amp;quot;: [&amp;quot;/bin/sh: 1: source: not found&amp;quot;], &amp;quot;stdout&amp;quot;: &amp;quot;&amp;quot;, &amp;quot;stdout_lines&amp;quot;: []}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이는 ansible은 기본적으로 &lt;code&gt;shell:&lt;/code&gt; 을 실행할 때, &lt;code&gt;/bin/bash&lt;/code&gt; 대신에 &lt;code&gt;/bin/sh&lt;/code&gt; 을 사용하기 때문에 그렇다.&lt;/p&gt;
&lt;p&gt;따라서 우리가 /bin/bash를 사용하도록 직접 지정해주면 해결된다. executable을 이용해 지정해 줄 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;- name: Virtual Env
  shell: source home/ubuntu/venv/bin/activate
  args:
    executable: /bin/bash&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;| &lt;a href=&quot;https://docs.ansible.com/ansible/2.5/modules/shell_module.html&quot;&gt;https://docs.ansible.com/ansible/2.5/modules/shell_module.html&lt;/a&gt;&lt;/p&gt;</description>
      <category>DevOps</category>
      <category>venv</category>
      <author>SSAMKO</author>
      <guid isPermaLink="true">https://ssamko.tistory.com/77</guid>
      <comments>https://ssamko.tistory.com/77#entry77comment</comments>
      <pubDate>Wed, 1 Dec 2021 14:36:42 +0900</pubDate>
    </item>
    <item>
      <title>[mac os]vagrant up시 `VBoxManage`Error 해결방법</title>
      <link>https://ssamko.tistory.com/76</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;virtualbox를 설치하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;vagrant 세팅 후 vagrant up으로 가상 머신을 생성하려고 할 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mac os에서는 아래와 같은 에러가 날 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1633835086419&quot; class=&quot;shell&quot; style=&quot;display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;==&amp;gt; default: Booting VM...
There was an error while executing `VBoxManage`, a CLI used by Vagrant
for controlling VirtualBox. The command and stderr is shown below.

Command: [&quot;startvm&quot;, &quot;91db4587-1e42-4b43-bdba-7b38c5055f05&quot;, &quot;--type&quot;, &quot;headless&quot;]

Stderr: VBoxManage: error: The virtual machine 'vagrant_study_default_1633830743228_76985' has terminated unexpectedly during startup with exit code 1 (0x1)
VBoxManage: error: Details: code NS_ERROR_FAILURE (0x80004005), component MachineWrap, interface IMachine&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mac os에서 해당 문제가 발생하는 원인은 대부분의 경우 권한 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정 &amp;gt; 보안 및 개인정보보호(Security &amp;amp; Privacy) &amp;gt; 일반(general) 에서 자물쇠를 해제한 후 '상세정보 보기'에서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Oracle 을 허용해주면 재시작하라는 메세지가 나오는데, 재시작해주고 나면 해결된다.&lt;/p&gt;</description>
      <category>DevOps</category>
      <category>Mac</category>
      <category>Vagrant</category>
      <category>virtualbox</category>
      <author>SSAMKO</author>
      <guid isPermaLink="true">https://ssamko.tistory.com/76</guid>
      <comments>https://ssamko.tistory.com/76#entry76comment</comments>
      <pubDate>Sun, 10 Oct 2021 12:07:36 +0900</pubDate>
    </item>
    <item>
      <title>[docker]boto3 사용시 Unable to locate credentials 에러 해결</title>
      <link>https://ssamko.tistory.com/75</link>
      <description>&lt;p&gt;docker와 boto3 혹은 botcore를 사용할 때, 아래와 같은 에러가 발생한다.&lt;br&gt;&lt;code&gt;botocore.exceptions.NoCredentialsError: Unable to locate credentials&lt;/code&gt;&lt;br&gt;~/.aws/credential에 접근할 수 없어서 발생하는 에러인데,&lt;br&gt;이때는 크게 두 가지 방법으로 해결할 수 있다.&lt;/p&gt;
&lt;p&gt;먼저, 단순히 &lt;code&gt;docker run&lt;/code&gt; 커맨드를 이용해서 docker를 사용중인 경우에는&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker run -v ~/.aws/:/root/.aws:ro {your_image} -e AWS_PROFILE=default&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 실행시켜주면 된다.&lt;/p&gt;
&lt;p&gt;만약, docker-compose를 사용중이라면,&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;services: 
  app:
    image: {docker-image-name}:latest
    volumes:
      - ~/.aws/:/root/.aws/:ro&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 이미지를 사용하거나&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;services: 
  app:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
      - ~/.aws/:/root/.aws/:ro&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 build와 command를 사용할 수 있다. (위 예제는 django)&lt;/p&gt;</description>
      <category>Docker</category>
      <category>AWS</category>
      <category>credential</category>
      <category>Django</category>
      <category>docker-compose</category>
      <author>SSAMKO</author>
      <guid isPermaLink="true">https://ssamko.tistory.com/75</guid>
      <comments>https://ssamko.tistory.com/75#entry75comment</comments>
      <pubDate>Tue, 7 Sep 2021 23:08:32 +0900</pubDate>
    </item>
    <item>
      <title>[github] access token으로 인증하기 - authentication</title>
      <link>https://ssamko.tistory.com/74</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 글을 찾아오셨다면 아마도 아래와 같은 오류를 보신 적이 있으실겁니다&lt;/p&gt;
&lt;pre id=&quot;code_1627459366491&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;remote: Password authentication is temporarily disabled as part of a brownout. Please use a personal access token instead.
remote: Please see https://github.blog/2020-07-30-token-authentication-requirements-for-api-and-git-operations/ for more information.
fatal: unable to access 'https://github.com/AI/frontend.git/': The requested URL returned error: 403&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;github에서 조만간 token만을 이용해 인증을 하겠다고 하니까 이참에 token 인증 방법을 익혀두시면 편하실거에요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;token을 사용하려면 먼저 token을 만들어 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;205&quot; data-origin-height=&quot;528&quot; data-filename=&quot;스크린샷 2021-07-28 오후 5.04.18.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cp559m/btraFEm1ZVm/AN0Q5CWihuqzq4qs7TQqI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cp559m/btraFEm1ZVm/AN0Q5CWihuqzq4qs7TQqI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cp559m/btraFEm1ZVm/AN0Q5CWihuqzq4qs7TQqI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcp559m%2FbtraFEm1ZVm%2FAN0Q5CWihuqzq4qs7TQqI1%2Fimg.png&quot; data-origin-width=&quot;205&quot; data-origin-height=&quot;528&quot; data-filename=&quot;스크린샷 2021-07-28 오후 5.04.18.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;profile &amp;gt; settings &amp;gt; developer settings &amp;gt; personal access token 으로 가서&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;245&quot; data-origin-height=&quot;203&quot; data-filename=&quot;스크린샷 2021-07-28 오후 5.05.05.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Z9SSJ/btraFFM4ApR/2ZXcR8JbBfk4Oxi1s5MyO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Z9SSJ/btraFFM4ApR/2ZXcR8JbBfk4Oxi1s5MyO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Z9SSJ/btraFFM4ApR/2ZXcR8JbBfk4Oxi1s5MyO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZ9SSJ%2FbtraFFM4ApR%2F2ZXcR8JbBfk4Oxi1s5MyO0%2Fimg.png&quot; data-origin-width=&quot;245&quot; data-origin-height=&quot;203&quot; data-filename=&quot;스크린샷 2021-07-28 오후 5.05.05.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽에 generate new token을 눌러줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Note에 토큰에 대한 설명을 넣어주고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;expiration에는 토큰의 사용기한을 넣어줍니다. 개인이 본인 컴퓨터에서만 쓸 목적이라면 No expiration을 해주셔도 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;scopes는 토큰의 권한 범위를 지정해주는 건데, 디테일한 설정이 필요없으신 분이라면 아래와 같이 체크해주시면 일반적으로 사용하는데에는 무리가 없습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;206&quot; data-origin-height=&quot;836&quot; data-filename=&quot;스크린샷 2021-07-28 오후 5.07.40.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sqN1F/btraInkBKtt/Wodc6e3SqkmIXtNPssTYy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sqN1F/btraInkBKtt/Wodc6e3SqkmIXtNPssTYy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sqN1F/btraInkBKtt/Wodc6e3SqkmIXtNPssTYy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsqN1F%2FbtraInkBKtt%2FWodc6e3SqkmIXtNPssTYy1%2Fimg.png&quot; data-origin-width=&quot;206&quot; data-origin-height=&quot;836&quot; data-filename=&quot;스크린샷 2021-07-28 오후 5.07.40.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 발급받은 토큰은 &lt;b&gt;딱 한번만 볼 수 있으니&lt;/b&gt; 잘 기록해두시기 바랍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토큰을 이용해 인증하는 방법은 remote를 지정할때 토큰을 입력해주는 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만일, 위와같은 에러문구를 보고 오셨다면,&lt;/p&gt;
&lt;pre id=&quot;code_1627459797042&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git remote set-url origin http://{token}@github.com/AI/frontend.git/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 origin remote의 url 앞에 token 정보를 넣어주시면 됩니다.&lt;/p&gt;</description>
      <category>IT알쓸신잡</category>
      <category>Git</category>
      <category>깃허브</category>
      <category>깃헙</category>
      <category>인증</category>
      <category>토큰</category>
      <author>SSAMKO</author>
      <guid isPermaLink="true">https://ssamko.tistory.com/74</guid>
      <comments>https://ssamko.tistory.com/74#entry74comment</comments>
      <pubDate>Wed, 28 Jul 2021 19:10:36 +0900</pubDate>
    </item>
    <item>
      <title>[django] migration file 초기화 하기</title>
      <link>https://ssamko.tistory.com/73</link>
      <description>&lt;p&gt;개발 초기에 model 이름을 변경한다던지 column을 추가한다던지 할 경우 기존의 migration 파일과 충돌이 나거나 migration파일이 지저분해지는 경우가 생기는데, 이럴때는 한번씩 migration file을 초기화 해주는 것이 좋다.&lt;/p&gt;
&lt;h3&gt;1. db 삭제&lt;/h3&gt;
&lt;p&gt;먼저 기존의 DB를 삭제해준다.&lt;/p&gt;
&lt;p&gt;(mariaDB/mysql)&lt;code&gt;DROP DATABASE {database};&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;2. 모든 migrations 스크립트 삭제&lt;/h3&gt;
&lt;p&gt;다음으로 모든 migrations 스크립트를 삭제한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;이때 주의할 점은 프로젝트 폴더 내에 가상환경(venv)이 있을 경우 가상환경 내의 migration 모듈이 함께 삭제되지 않도록 해주어야한다. (아래 참고)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;1. project home 디렉토리로 이동&lt;/p&gt;
&lt;p&gt;2. &lt;code&gt;find . -path &amp;quot;\*/migrations/\*.py&amp;quot; -not -name &amp;quot;\_\_init\_\_.py&amp;quot; -not -path &amp;quot;./venv/\*&amp;quot; -delete&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;가상환경 내 migration모듈이 함께 삭제되지 않도록 실행전-delete옵션을 빼고 확인&lt;/p&gt;
&lt;p&gt;3. &lt;code&gt;find . -path &amp;quot;\*/migrations/\*.pyc&amp;quot; -delete&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;3. makemigrations&lt;/h3&gt;
&lt;p&gt;다시 &lt;code&gt;makemigrations&lt;/code&gt;를 실행해서 새로운 migration file을 생성한다.&lt;/p&gt;</description>
      <category>Django</category>
      <category>makemigrations</category>
      <category>migrate</category>
      <author>SSAMKO</author>
      <guid isPermaLink="true">https://ssamko.tistory.com/73</guid>
      <comments>https://ssamko.tistory.com/73#entry73comment</comments>
      <pubDate>Fri, 2 Jul 2021 20:11:32 +0900</pubDate>
    </item>
    <item>
      <title>[Django] rest_framework APIClient 'json' 사용시 request 처리</title>
      <link>https://ssamko.tistory.com/72</link>
      <description>&lt;p&gt;아래와 같이 test코드를 짤 때, APIClient를 활용해 post로 보내면서 format을 &amp;#39;json&amp;#39;으로 지정해주면&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from rest_framework.test import APIClient
client = APIClient()
response = client.post(&amp;quot;/api/hi/&amp;quot;, {&amp;quot;some&amp;quot;:&amp;quot;data&amp;quot;}, format=&amp;quot;json&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;view에서 처리할때는 request.POST대신 request.body를 사용해서 받아주면 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;class DockingView(View):
    def post(self, request):
        body = request.body
        # body = {&amp;quot;some&amp;quot;:&amp;quot;data&amp;quot;}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Django</category>
      <author>SSAMKO</author>
      <guid isPermaLink="true">https://ssamko.tistory.com/72</guid>
      <comments>https://ssamko.tistory.com/72#entry72comment</comments>
      <pubDate>Thu, 1 Jul 2021 20:26:46 +0900</pubDate>
    </item>
    <item>
      <title>[Flutter] geolocator - ios simulator에서 PlatformException(ERROR_UPDATING_LOCATION)오류 해결</title>
      <link>https://ssamko.tistory.com/71</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;flutter_logo.png&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1000&quot; width=&quot;200&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Fl6m8/btq2MAzr5Kk/74K5xXnD2N5NNNjnK0sPzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Fl6m8/btq2MAzr5Kk/74K5xXnD2N5NNNjnK0sPzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Fl6m8/btq2MAzr5Kk/74K5xXnD2N5NNNjnK0sPzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFl6m8%2Fbtq2MAzr5Kk%2F74K5xXnD2N5NNNjnK0sPzk%2Fimg.png&quot; data-filename=&quot;flutter_logo.png&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1000&quot; width=&quot;200&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;flutter 패키지 중 하나인 geolocator를 이용해서 현재 위치location를 가져올 때, 정상적으로 Info.plist에 권한요청을 했음에도 오류가 나는 경우가 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;0.issue.jpg&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;128&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nzlZ8/btq2M3g0SDM/r8JPfMzsky7euDvNte0Jl0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nzlZ8/btq2M3g0SDM/r8JPfMzsky7euDvNte0Jl0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nzlZ8/btq2M3g0SDM/r8JPfMzsky7euDvNte0Jl0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnzlZ8%2Fbtq2M3g0SDM%2Fr8JPfMzsky7euDvNte0Jl0%2Fimg.jpg&quot; data-filename=&quot;0.issue.jpg&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;128&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PlatformException(ERROR_UPDATING_LOCATION)&lt;/code&gt;에러가 발생하는데, 시뮬레이터 상에서 location 정보를 가져오지 못해서 발생하는 에러다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;ios시뮬레이터(12.04 기준)에서 Features &amp;gt; Location &amp;gt;&amp;nbsp; Any(free drive, Apple ...) 설정을 해주면, 시뮬레이터가 정상적으로 해당하는 location정보를 불러온다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;참고: &lt;a href=&quot;https://github.com/Baseflow/flutter-geolocator/issues/190&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.com/Baseflow/flutter-geolocator/issues/190&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618715829030&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Exception on IOS &amp;middot; Issue #190 &amp;middot; Baseflow/flutter-geolocator&quot; data-og-description=&quot;  Bug Report I'm using the stream feature for real time location updates and I ran into an issue. When my position is fixed in the simulator, the update works normally but when I set the locati...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Baseflow/flutter-geolocator/issues/190&quot; data-og-url=&quot;https://github.com/Baseflow/flutter-geolocator/issues/190&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gpSge/hyJU1tdwFm/bK8YoC1MjMtbsJs5fAHum0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://github.com/Baseflow/flutter-geolocator/issues/190&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Baseflow/flutter-geolocator/issues/190&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gpSge/hyJU1tdwFm/bK8YoC1MjMtbsJs5fAHum0/img.png?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;Exception on IOS &amp;middot; Issue #190 &amp;middot; Baseflow/flutter-geolocator&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;  Bug Report I'm using the stream feature for real time location updates and I ran into an issue. When my position is fixed in the simulator, the update works normally but when I set the locati...&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Flutter</category>
      <category>Geolocator</category>
      <category>Location</category>
      <category>시뮬레이터</category>
      <category>플러터</category>
      <author>SSAMKO</author>
      <guid isPermaLink="true">https://ssamko.tistory.com/71</guid>
      <comments>https://ssamko.tistory.com/71#entry71comment</comments>
      <pubDate>Sun, 18 Apr 2021 12:19:21 +0900</pubDate>
    </item>
    <item>
      <title>[Flutter] 이전 버전에서 패키지 추가 이슈 - 'requires your app to be migrated to the Android embedding v2'</title>
      <link>https://ssamko.tistory.com/70</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;flutter_logo.png&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1000&quot; width=&quot;200&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bl0G4l/btq2OODcoeZ/xZNQ1mvQS9l97JBFoJwtk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bl0G4l/btq2OODcoeZ/xZNQ1mvQS9l97JBFoJwtk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bl0G4l/btq2OODcoeZ/xZNQ1mvQS9l97JBFoJwtk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbl0G4l%2Fbtq2OODcoeZ%2FxZNQ1mvQS9l97JBFoJwtk1%2Fimg.png&quot; data-filename=&quot;flutter_logo.png&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;1000&quot; width=&quot;200&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이전 버전에서 제작된 플러터 프로젝트에서 패키지를 추가하려고 할 때,&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;0.add_package.jpg&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;157&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dIxHwv/btq2lp4OhKL/1SNy1n4GjYhbeytKVf4zq1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dIxHwv/btq2lp4OhKL/1SNy1n4GjYhbeytKVf4zq1/img.jpg&quot; data-alt=&quot;audioplayers를 추가하고 싶다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dIxHwv/btq2lp4OhKL/1SNy1n4GjYhbeytKVf4zq1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdIxHwv%2Fbtq2lp4OhKL%2F1SNy1n4GjYhbeytKVf4zq1%2Fimg.jpg&quot; data-filename=&quot;0.add_package.jpg&quot; data-origin-width=&quot;200&quot; data-origin-height=&quot;157&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;audioplayers를 추가하고 싶다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;아래와 같은 이슈가 발생한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;1.warning.jpg&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;261&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/B1Syy/btq2lBYyvjq/HKBVBJr0wp8HCTEEc1SQhK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/B1Syy/btq2lBYyvjq/HKBVBJr0wp8HCTEEc1SQhK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/B1Syy/btq2lBYyvjq/HKBVBJr0wp8HCTEEc1SQhK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FB1Syy%2Fbtq2lBYyvjq%2FHKBVBJr0wp8HCTEEc1SQhK%2Fimg.jpg&quot; data-filename=&quot;1.warning.jpg&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;261&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;android embedding 버전이 맞지 않아서 생기는 이슈인데, 몇가지 조치를 취해주면 해결할 수 있다.&lt;/p&gt;
&lt;p&gt;먼저, MainActivity.java를 수정해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;2.path_to_mainactivity.jpg&quot; data-origin-width=&quot;325&quot; data-origin-height=&quot;208&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVrVeL/btq2hDwtZFN/0YQWcSupMXJ0igF1rNGKsK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVrVeL/btq2hDwtZFN/0YQWcSupMXJ0igF1rNGKsK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVrVeL/btq2hDwtZFN/0YQWcSupMXJ0igF1rNGKsK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVrVeL%2Fbtq2hDwtZFN%2F0YQWcSupMXJ0igF1rNGKsK%2Fimg.jpg&quot; data-filename=&quot;2.path_to_mainactivity.jpg&quot; data-origin-width=&quot;325&quot; data-origin-height=&quot;208&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;아래의 원본 코드를&lt;/p&gt;
&lt;pre id=&quot;code_1618131022281&quot; class=&quot;java&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package co.appbrewery.magic8ball;

import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;

public class MainActivity extends FlutterActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    GeneratedPluginRegistrant.registerWith(this);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;아래와 같이 수정해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1618131115896&quot; class=&quot;java&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package co.appbrewery.magic8ball;

import io.flutter.embedding.android.FlutterActivity;

public class MainActivity extends FlutterActivity {
 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그다음 AndroidManifest.xml파일도 수정해준다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;3.path_to_manifest.jpg&quot; data-origin-width=&quot;283&quot; data-origin-height=&quot;164&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWgJkl/btq2plOmbTj/Y1lOUj11mW026RFEXL9P51/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWgJkl/btq2plOmbTj/Y1lOUj11mW026RFEXL9P51/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWgJkl/btq2plOmbTj/Y1lOUj11mW026RFEXL9P51/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWgJkl%2Fbtq2plOmbTj%2FY1lOUj11mW026RFEXL9P51%2Fimg.jpg&quot; data-filename=&quot;3.path_to_manifest.jpg&quot; data-origin-width=&quot;283&quot; data-origin-height=&quot;164&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;아래의 원본 코드에서 &amp;lt;application&amp;gt;과 그 아래의 &amp;lt;meta-data&amp;gt;부분을 수정해준다.&lt;/p&gt;
&lt;p&gt;원본&lt;/p&gt;
&lt;pre id=&quot;code_1618131364965&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...
&amp;lt;application
        android:name=&quot;io.flutter.app.FlutterApplication&quot;
        android:label=&quot;magic_8_ball&quot;
        android:icon=&quot;@mipmap/ic_launcher&quot;&amp;gt;
       	&amp;lt;activity
        	...&amp;gt;
        &amp;lt;meta-data
                android:name=&quot;io.flutter.app.android.SplashScreenUntilFirstFrame&quot;
                android:value=&quot;true&quot; /&amp;gt;
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;아래와 같이 수정해준다. &amp;lt;application&amp;gt;의 android:name을 삭제하고, &amp;lt;meta-data&amp;gt;의 android:name과 android:value값을 변경한다.&lt;/p&gt;
&lt;pre id=&quot;code_1618131490266&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...
&amp;lt;application
        android:label=&quot;magic_8_ball&quot;
        android:icon=&quot;@mipmap/ic_launcher&quot;&amp;gt;
       	&amp;lt;activity
        	...&amp;gt;
        &amp;lt;meta-data
                android:name=&quot;flutterEmbedding&quot;
                android:value=&quot;2&quot; /&amp;gt;
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;수정 후 아래 커맨드를 이용해 패키지를 다시 불러오면 정상적으로 패키지가 불러지는 것을 확인할 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;$flutter pub get&amp;nbsp;&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;참고: &lt;a href=&quot;https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1618130907019&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;flutter/flutter&quot; data-og-description=&quot;Flutter makes it easy and fast to build beautiful apps for mobile and beyond. - flutter/flutter&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects&quot; data-og-url=&quot;https://github.com/flutter/flutter&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b97khv/hyJQLwYd5L/pb49SmrM8D1rcKN8oPkzP1/img.png?width=1386&amp;amp;height=640&amp;amp;face=0_0_1386_640,https://scrap.kakaocdn.net/dn/bCMqTB/hyJQNhfsTB/tDbgu2ZNRSaaevOHVSZ0pK/img.png?width=800&amp;amp;height=436&amp;amp;face=0_0_800_436,https://scrap.kakaocdn.net/dn/bG7zAC/hyJQHOSjK2/nM9rZKrfp5F6LJg6qa6H7k/img.png?width=600&amp;amp;height=407&amp;amp;face=0_0_600_407&quot;&gt;&lt;a href=&quot;https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b97khv/hyJQLwYd5L/pb49SmrM8D1rcKN8oPkzP1/img.png?width=1386&amp;amp;height=640&amp;amp;face=0_0_1386_640,https://scrap.kakaocdn.net/dn/bCMqTB/hyJQNhfsTB/tDbgu2ZNRSaaevOHVSZ0pK/img.png?width=800&amp;amp;height=436&amp;amp;face=0_0_800_436,https://scrap.kakaocdn.net/dn/bG7zAC/hyJQHOSjK2/nM9rZKrfp5F6LJg6qa6H7k/img.png?width=600&amp;amp;height=407&amp;amp;face=0_0_600_407');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;flutter/flutter&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Flutter makes it easy and fast to build beautiful apps for mobile and beyond. - flutter/flutter&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Flutter</category>
      <author>SSAMKO</author>
      <guid isPermaLink="true">https://ssamko.tistory.com/70</guid>
      <comments>https://ssamko.tistory.com/70#entry70comment</comments>
      <pubDate>Sun, 11 Apr 2021 18:00:48 +0900</pubDate>
    </item>
    <item>
      <title>[python] 병렬 작업 처리 | 비동기 처리 - threading, asyncio</title>
      <link>https://ssamko.tistory.com/69</link>
      <description>&lt;p&gt;회사에서 AI모듈 패키징을 하며, 여러 대의 GPU를 효율적으로 사용하는 방법에 대한 고민이 있었다.&lt;/p&gt;
&lt;p&gt;각각의 아이템들에 특정 gpu index를 부여해서, 해당 gpu에서 작업하도록 하는 방법을 사용중이었는데, (Round Robin Load Balancing Algorithm과 유사)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;435&quot; data-origin-height=&quot;316&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uJYHf/btqXRvvPwmg/BOn0XsaNWmHUW7Zk4mIk3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uJYHf/btqXRvvPwmg/BOn0XsaNWmHUW7Zk4mIk3k/img.png&quot; data-alt=&quot;기존 multi GPU 활용방법&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uJYHf/btqXRvvPwmg/BOn0XsaNWmHUW7Zk4mIk3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuJYHf%2FbtqXRvvPwmg%2FBOn0XsaNWmHUW7Zk4mIk3k%2Fimg.png&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;435&quot; data-origin-height=&quot;316&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;기존 multi GPU 활용방법&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이 방법은 놀고 있는 gpu가 있어도 특정 gpu에 업무가 몰릴 수 있다는 단점이 있었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그래서 각 아이템에 gpu_index를 부여하는 대신, 아이템이 업로드 되면 대기중인 gpu를 찾아서 해당 아이템의 처리를 하게 하는 방식으로 로직을 다시 작성할 필요가 있었다. (Least Connections Load Balancing Algorithm과 유사)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;(물론, 이 방법을 처음부터 생각하지 못한 것은 아니었지만, 구현이 좀 더 복잡해서 미뤄뒀던 것이다.)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;생각해낸 해결책은&lt;/p&gt;
&lt;p&gt;감독Director과 작업자Worker를 두고,&amp;nbsp;&lt;/p&gt;
&lt;p&gt;감독이 1) 처리할 아이템이 있는지 확인하고, 2) 대기중인 GPU가 있다면, 3) Worker를 생성해서 해당 아이템을 처리하도록 한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그리고 4) Worker가 작업이 끝났는지 확인해서 작업이 끝난 Worker는 삭제한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;작업자Worker는 생성되면 1) 아이템을 처리하고, 처리가 완료되면 2) 완료 상태로 바꾼다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;multiGPU.jpg&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wN7a9/btqXyMd56Be/q9S68P7hiaJbq8KV1cmss0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wN7a9/btqXyMd56Be/q9S68P7hiaJbq8KV1cmss0/img.jpg&quot; data-alt=&quot;Director와 Worker의 관계도&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wN7a9/btqXyMd56Be/q9S68P7hiaJbq8KV1cmss0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwN7a9%2FbtqXyMd56Be%2Fq9S68P7hiaJbq8KV1cmss0%2Fimg.jpg&quot; data-filename=&quot;multiGPU.jpg&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;540&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Director와 Worker의 관계도&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이 로직을 구현하기 위해서는 비동기 처리가 필요했다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;처음엔 이 비동기 처리를 위해서 asyncio를 이용했다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;하지만, 이 asyncio로 비동기 처리는 됐지만, await로 각 비동기 프로세스들이 종료되기를 기다리는 부분이 있어야 한다는 문제가 있었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Director는 계속해서 본인의 할 일을 하고,&lt;/p&gt;
&lt;p&gt;Worker는 자기 작업을 마치고 빠지면 되는 것인데,&lt;/p&gt;
&lt;p&gt;Director가 각 Worker들의 작업이 다 끝나길 기다리면 이 로직이 성립되지 않는 것이었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그래서 다른 방법을 고민하다가 각각의 처리를 개별 thread로 처리하는 방안을 생각해냈다.&lt;/p&gt;
&lt;p&gt;Worker클래스를 threading.Thread의 하위 클래스로 만들어서 thread를 실행시키고, 실행이 끝난 Worker는 소멸시키는 방법이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이 방법을 적용하니 Director는 메인 thread로 돌고, 각각의 Worker들이 독립적인 sub thread로 작업을 하면서,&lt;/p&gt;
&lt;p&gt;원하던대로 작동하게 되었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이런 처리가 필요한 상황이 많을 것 같아 범용 모듈로 만들었다.&lt;/p&gt;
&lt;p&gt;스크립트가 궁금한 사람은 아래 링크에서 확인하기 바랍니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;더불어 더 좋은 아이디어나 개선점이 있다면 알려주시기 바랍니다 :)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/teacherSsamko/DirectorWorker&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.com/teacherSsamko/DirectorWorker&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1613551473618&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;teacherSsamko/DirectorWorker&quot; data-og-description=&quot;Director and Worker. using thread. Contribute to teacherSsamko/DirectorWorker development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/teacherSsamko/DirectorWorker&quot; data-og-url=&quot;https://github.com/teacherSsamko/DirectorWorker&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/N5Roq/hyJiA4SbiE/HHqzYilgMlCXkxYnSXGug1/img.jpg?width=400&amp;amp;height=400&amp;amp;face=148_47_195_98&quot;&gt;&lt;a href=&quot;https://github.com/teacherSsamko/DirectorWorker&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/teacherSsamko/DirectorWorker&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/N5Roq/hyJiA4SbiE/HHqzYilgMlCXkxYnSXGug1/img.jpg?width=400&amp;amp;height=400&amp;amp;face=148_47_195_98');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;teacherSsamko/DirectorWorker&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Director and Worker. using thread. Contribute to teacherSsamko/DirectorWorker development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;thread에 관해서 궁금하신 분은 아래 위키피디아를 확인해보세요&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%8A%A4%EB%A0%88%EB%93%9C_(%EC%BB%B4%ED%93%A8%ED%8C%85)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ko.wikipedia.org/wiki/%EC%8A%A4%EB%A0%88%EB%93%9C_(%EC%BB%B4%ED%93%A8%ED%8C%85)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1613720991535&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;스레드 (컴퓨팅) - 위키백과, 우리 모두의 백과사전&quot; data-og-description=&quot;위키백과, 우리 모두의 백과사전. 두 개의 스레드를 실행하고 있는 하나의 프로세스. 스레드(thread)는 어떠한 프로그램 내에서, 특히 프로세스 내에서 실행되는 흐름의 단위를 말한다. 일반적으&quot; data-og-host=&quot;ko.wikipedia.org&quot; data-og-source-url=&quot;https://ko.wikipedia.org/wiki/%EC%8A%A4%EB%A0%88%EB%93%9C_(%EC%BB%B4%ED%93%A8%ED%8C%85)&quot; data-og-url=&quot;https://ko.wikipedia.org/wiki/%EC%8A%A4%EB%A0%88%EB%93%9C_(%EC%BB%B4%ED%93%A8%ED%8C%85)&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/drHMQP/hyJkPF0c4z/9oOKgqXuZeiBjqba2dRizK/img.png?width=1200&amp;amp;height=1133&amp;amp;face=0_0_1200_1133&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%8A%A4%EB%A0%88%EB%93%9C_(%EC%BB%B4%ED%93%A8%ED%8C%85)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.wikipedia.org/wiki/%EC%8A%A4%EB%A0%88%EB%93%9C_(%EC%BB%B4%ED%93%A8%ED%8C%85)&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/drHMQP/hyJkPF0c4z/9oOKgqXuZeiBjqba2dRizK/img.png?width=1200&amp;amp;height=1133&amp;amp;face=0_0_1200_1133');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;스레드 (컴퓨팅) - 위키백과, 우리 모두의 백과사전&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;위키백과, 우리 모두의 백과사전. 두 개의 스레드를 실행하고 있는 하나의 프로세스. 스레드(thread)는 어떠한 프로그램 내에서, 특히 프로세스 내에서 실행되는 흐름의 단위를 말한다. 일반적으&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;ko.wikipedia.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Python</category>
      <category>gpu 병렬처리</category>
      <category>multi gpu</category>
      <category>동시</category>
      <category>비동기</category>
      <category>파이썬</category>
      <author>SSAMKO</author>
      <guid isPermaLink="true">https://ssamko.tistory.com/69</guid>
      <comments>https://ssamko.tistory.com/69#entry69comment</comments>
      <pubDate>Wed, 17 Feb 2021 20:45:55 +0900</pubDate>
    </item>
    <item>
      <title>[ubuntu] ssh tunneling - systemd로 관리하기</title>
      <link>https://ssamko.tistory.com/68</link>
      <description>&lt;p&gt;local에서 remote로 혹은 remote에서 remote로 보안을 유지하며 통신하기 위해 ssh tunneling을 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이 ssh tunneling을 항상 작동시키고 싶다면&amp;nbsp;&lt;/p&gt;
&lt;p&gt;가장 쉬운 방법은 systemd를 활용하는 것이다. 아래와 같은 스크립트를 작성해서 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1612752959787&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[Unit]
Description=ssh tunneling
After=multi-user.target

[Service]
User=ssamko
Type=simple
WorkingDirectory = /home/ssamko/
ExecStart = /usr/bin/ssh -i /home/ssamko/.ssh/ssamko -nNT -L 8585:127.0.0.1:3306 35.35.35.35
Restart = always
RestartSec = 1min

[Install]
WantedBy=multi-user.target&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ssh tunneling 커맨드는&lt;/p&gt;
&lt;pre id=&quot;code_1612753053319&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ssh -i {your_public_key} -nNT -L {A}:{B_LOCAL_IP}:{B_PORT} {B_REMOTE_IP}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A: 현재 서버에서 ssh tunnel로 사용할 포트번호&lt;/p&gt;
&lt;p&gt;B_LOCAL_IP: 접속할 대상 서버의 로컬 ip&lt;/p&gt;
&lt;p&gt;B_PORT: 접속할 대상 서버의 포트&lt;/p&gt;
&lt;p&gt;B_REMOTE_IP: 접속할 대상 서버의 remote ip&lt;/p&gt;</description>
      <category>IT알쓸신잡</category>
      <category>Service</category>
      <category>systemctl</category>
      <category>우분투</category>
      <category>터널</category>
      <category>터널링</category>
      <author>SSAMKO</author>
      <guid isPermaLink="true">https://ssamko.tistory.com/68</guid>
      <comments>https://ssamko.tistory.com/68#entry68comment</comments>
      <pubDate>Mon, 8 Feb 2021 20:59:22 +0900</pubDate>
    </item>
  </channel>
</rss>