์ฝ”๋“œ - ํŒจ์บ  ์ˆ˜์—… ์ฝ”๋“œ ์ฐธ๊ณ  (ํŒจ์บ  ์ˆ˜์—… ์ •๋ฆฌ)

 

 

<์ด์ „ ๊ธ€>

https://silvercoding.tistory.com/30

 

[python ์‹ฌํ™”] 13. ์ฝ”๋ฃจํ‹ด (coroutine) , yield from

์ฝ”๋“œ - ํŒจ์บ  ์ˆ˜์—… ์ฝ”๋“œ ์ฐธ๊ณ  (ํŒจ์บ  ์ˆ˜์—… ์ •๋ฆฌ) <์ด์ „ ๊ธ€> https://silvercoding.tistory.com/29 https://silvercoding.tistory.com/28 https://silvercoding.tistory.com/27 https://silvercoding.tistory.com/26..

silvercoding.tistory.com

 

* Future ๋™์‹œ์„ฑ / ๋น„๋™๊ธฐ ์ž‘์—… ์‹คํ–‰ 

์ง€์—ฐ์‹œ๊ฐ„ (Block) CPU ๋ฐ ๋ฆฌ์†Œ์Šค ๋‚ญ๋น„ ๋ฐฉ์ง€ -> (FILE) Network I/O๊ด€๋ จ ์ž‘์—… ๋™์‹œ์„ฑ ํ™œ์šฉ ๊ถŒ์žฅ 

: ์ ํ•ฉํ•œ ์ž‘์—…์ผ ๊ฒฝ์šฐ ์ˆœ์ฐจ ์ง„ํ–‰๋ณด๋‹ค ์••๋„์ ์œผ๋กœ ์„ฑ๋Šฅ ํ–ฅ์ƒ 

 

 

 

* ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ ์‹ค์Šตํ•  3๊ฐ€์ง€ 

1. ์ˆœ์ฐจ ์‹คํ–‰ 

2. concurrent.futures ๋ฐฉ๋ฒ•1 

3. concurrent.futures ๋ฐฉ๋ฒ• 2 

 

import os 
import time # ์„ฑ๋Šฅ์ธก์ • 
import sys
import csv
# ๊ตญ๊ฐ€ ์ •๋ณด 
NATION_LS = ('Singapore Germany Israel Norway Italy Canada France Spain Maxico').split()
# ์ดˆ๊ธฐ CSV ์œ„์น˜ 
TARGET_CSV = './resources/nations.csv'
# ์ €์žฅ ํด๋” ์œ„์น˜ 
DEST_DIR = './csvs'
# CSV ํ—ค๋” ๊ธฐ์ดˆ ์ •๋ณด 
HEADER = ['Region','Country','Item Type','Sales Channel','Order Priority','Order Date','Order ID','Ship Date','Units Sold','Unit Price','Unit Cost','Total Revenue','Total Cost','Total Profit']

<csv ํŒŒ์ผ : ํŒจ์ŠคํŠธ ์บ ํผ์Šค ์ œ๊ณต>

NATION_LS : ์‚ฌ์šฉํ•  ๊ตญ๊ฐ€ ์ด๋ฆ„ ๋ฆฌ์ŠคํŠธ 

TARGET_CSV : csvํŒŒ์ผ์ด ์žˆ๋Š” ์œ„์น˜ ๊ฒฝ๋กœ 

DEST_DIR : ์ตœ์ข…์ ์œผ๋กœ csvํŒŒ์ผ์ด ์ €์žฅ๋  ํด๋” ์œ„์น˜ ๊ฒฝ๋กœ 

HEADER : csv์˜ ํ—ค๋”๋ฅผ ์ถ”์ถœ ํ•ด๋†“์€ ๋ฆฌ์ŠคํŠธ 

 

 

 

- 1. ์ˆœ์ฐจ์‹คํ–‰ ์˜ˆ์ œ 

ํฌ์ŠคํŒ…์—์„œ๋Š” ์ฐจ๋ก€๋Œ€๋กœ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜์ง€๋งŒ ๊ณต๋ถ€ํ•  ๋•Œ๋Š” ๋’ค์—์„œ๋ถ€ํ„ฐ( (6) ๋ถ€ํ„ฐ ) ๊ฑฐ์Šฌ๋Ÿฌ์˜ค๋ฉฐ ๊ณต๋ถ€ํ•˜๊ธฐ

 

 

(1) ๊ตญ๊ฐ€๋ณ„ CSV ํŒŒ์ผ ์ €์žฅ 

def save_csv(data, filename):
    # ์ตœ์ข… ๊ฒฝ๋กœ ์ƒ์„ฑ 
    path = os.path.join(DEST_DIR, filename)

    with open(path, 'w', newline="") as fp:
        writer = csv.DictWriter(fp, fieldnames=HEADER)
        # Header Write
        writer.writeheader()
        # Dict to CSV write
        for row in data: 
            writer.writerow(row)

์ตœ์ข… csvํŒŒ์ผ์„ ์ €์žฅํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค. ๊ตญ๊ฐ€๋ณ„๋กœ ๋งŒ๋“ค์–ด์ง„ ๋ฐ์ดํ„ฐ(data)์™€ ์ƒ์„ฑํ•  ํŒŒ์ผ์ด๋ฆ„(filename)์„ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค. 

 

 

(2) ๊ตญ๊ฐ€๋ณ„ ๋ถ„๋ฆฌ 

def get_sales_data(nt):
    with open(TARGET_CSV, 'r') as f:
        reader = csv.DictReader(f)
        # Dict๋ฅผ ๋ฆฌ์ŠคํŠธ๋กœ ์ ์žฌ 
        data = []
        # Header ํ™•์ธ 
        # print(reader.fieldnames)
        for r in reader:
            # OrderedDict ํ™•์ธ 
            # print(r)
            # ์กฐ๊ฑด์— ๋งž๋Š” ๊ตญ๊ฐ€๋งŒ ์‚ฝ์ž… 
            if r['Country'] == nt:
                data.append(r)
    return data

๊ตญ๊ฐ€์˜ ์ด๋ฆ„(nt)์„ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค. csvํŒŒ์ผ์„ ์—ด์–ด์„œ DictReader๋กœ reader์— ๋ฐ›์•„์ค€๋‹ค. Country๊ฐ€ nt๊ตญ๊ฐ€์ผ ๋•Œ data๋ฆฌ์ŠคํŠธ์— r์„ ๋„ฃ์–ด์ค€๋‹ค.  ์ด๋ ‡๊ฒŒ ๊ตญ๊ฐ€๋ณ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„๋ฆฌํ•ด ์ฃผ๋Š” ํ•จ์ˆ˜์ด๋‹ค. 

 

 

(3) ์ค‘๊ฐ„ ์ƒํ™ฉ ์ถœ๋ ฅ

def show(text):
    print(text, end=' ')
    # ์ค‘๊ฐ„ ์ถœ๋ ฅ (๋ฒ„ํผ ๋น„์šฐ๊ธฐ)
    sys.stdout.flush()

๊ตญ๊ฐ€์˜ ์ด๋ฆ„์„ ๋ฐ›์•„์„œ ํ„ฐ๋ฏธ๋„์— ์ถœ๋ ฅํ•ด ์ฃผ์–ด ์ง„ํ–‰์ƒํ™ฉ์„ ์•Œ๋ ค์ฃผ๋Š” ํ•จ์ˆ˜์ด๋‹ค. 

 

 

(4) ๊ตญ๊ฐ€ ๋ณ„ ๋ถ„๋ฆฌ ํ•จ์ˆ˜ ์‹คํ–‰ - (1) , (2) , (3) ํ•จ์ˆ˜ ์‚ฌ์šฉ

def separate_many(nt_list):
    for nt in sorted(nt_list):
        # ๋ถ„๋ฆฌ ๋ฐ์ดํ„ฐ 
        data = get_sales_data(nt)
        # ์ƒํ™ฉ ์ถœ๋ ฅ 
        show(nt)
        # ํŒŒ์ผ ์ €์žฅ 
        save_csv(data, nt.lower() + '.csv')

    return len(nt_list)

์—ฌ๊ธฐ์„œ for๋ฌธ์œผ๋กœ ๊ฐ ๊ตญ๊ฐ€๋ณ„ ์ด๋ฆ„์„ ์•ž์—์„œ ๋ณด์•˜๋˜ get_sales_data์— ๋„ฃ์–ด์ฃผ์–ด ๋ถ„๋ฆฌ๋œ ๋ฐ์ดํ„ฐ๋ฅผ csvํŒŒ์ผ๋กœ ์ €์žฅํ•ด์ฃผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ ๋‹ค. showํ•จ์ˆ˜๋กœ ์ง„ํ–‰์ƒํ™ฉ์„ ์ถœ๋ ฅํ•˜๊ณ , save_csvํ•จ์ˆ˜๋กœ ๊ฐ ๊ตญ๊ฐ€๋ณ„ csvํŒŒ์ผ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•œ๋‹ค. 

 

 

(5) ์‹œ๊ฐ„ ์ธก์ • ๋ฐ ๋ฉ”์ธํ•จ์ˆ˜ - (4) ํ•จ์ˆ˜ ์‚ฌ์šฉ

def main(separate_many):
    # ์‹œ์ž‘ ์‹œ๊ฐ„ 
    start_tm = time.time()
    # ๊ฒฐ๊ณผ ๊ฑด์ˆ˜ 
    result_cnt = separate_many(NATION_LS)
    # ์ข…๋ฃŒ ์‹œ๊ฐ„ 
    end_tm = time.time() - start_tm 

    msg = '\n{} csv separated in {:.2f}s'

    # ์ตœ์ข… ๊ฒฐ๊ณผ ์ถœ๋ ฅ 
    print(msg.format(result_cnt, end_tm))

๋“œ๋””์–ด mainํ•จ์ˆ˜์—์„œ๋Š” separate_manyํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตญ๊ฐ€๋ณ„ csvํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๋„๋ก ํ•˜๊ณ  , ์ด์— ๋Œ€ํ•œ ์‹œ๊ฐ„์„ ์ธก์ •ํ•˜์—ฌ ์ถœ๋ ฅํ•ด์ค€๋‹ค. 

 

 

(6) ์‹คํ–‰ - (5) ํ•จ์ˆ˜ ์‚ฌ์šฉ

if __name__ == '__main__':
    main(separate_many)

Canada France Germany Israel Italy Maxico Norway Singapore Spain
9 csv separated in 21.09s

์ด๋ ‡๊ฒŒ mainํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด ์ฃผ๋ฉด ์•ž์—์„œ ๋งŒ๋“ค์–ด ๋†“์•˜๋˜ ํ•จ์ˆ˜๋“ค์ด ๋ชจ๋‘ ์‹คํ–‰๋˜๋ฉฐ 

๊ตญ๊ฐ€๋ณ„ csv ํŒŒ์ผ์ด ๋ชจ๋‘ ๋งŒ๋“ค์–ด ์ง„๋‹ค. 

 

 

 

 

 

 

 

 

 

 

 

 

*** Google Python GIL (Global Interpreter Lock) 

: GIL์€ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋งŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ธํ„ฐํ”„๋ฆฌํ„ฐ ์ž์ฒด์—์„œ ๋ฝ์„ ๊ฑฐ๋Š” ๊ฒƒ์ด๋‹ค. 

 

<python GIL ๊ด€๋ จ๋ฌธ์„œ>

https://wiki.python.org/moin/GlobalInterpreterLock

 

GlobalInterpreterLock - Python Wiki

In CPython, the global interpreter lock, or GIL, is a mutex that protects access to Python objects, preventing multiple threads from executing Python bytecodes at once. The GIL prevents race conditions and ensures thread safety. A nice explanation of how t

wiki.python.org

 

 

- 2. concurrent.futures ๋ฐฉ๋ฒ•1 (ThreadPoolExecutor, ProcessPoolExecutor)

<concurent.futures ์ฐธ๊ณ ๋ฌธ์„œ>

https://docs.python.org/ko/3.7/library/concurrent.futures.html

 

concurrent.futures — ๋ณ‘๋ ฌ ์ž‘์—… ์‹คํ–‰ํ•˜๊ธฐ — Python 3.7.11 ๋ฌธ์„œ

์†Œ์Šค ์ฝ”๋“œ: Lib/concurrent/futures/thread.py์™€ Lib/concurrent/futures/process.py concurrent.futures ๋ชจ๋“ˆ์€ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฝœ๋Ÿฌ๋ธ”์„ ์‹คํ–‰ํ•˜๋Š” ๊ณ ์ˆ˜์ค€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋น„๋™๊ธฐ ์‹คํ–‰์€ (ThreadPoolExecutor๋ฅผ ์‚ฌ์šฉ

docs.python.org

: map() ์‚ฌ์šฉ

: ์„œ๋กœ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ ๋˜๋Š” ํ”„๋กœ์„ธ์Šค์—์„œ ์‹คํ–‰ ๊ฐ€๋Šฅ 

: ๋‚ด๋ถ€ ๊ณผ์ •์„ ์•Œ ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ , ๊ณ ์ˆ˜์ค€์œผ๋กœ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•จ . 

...
from concurrent import futures

concurrent์˜ futres ๋ฅผ ์ถ”๊ฐ€๋กœ import ํ•ด์ค€๋‹ค. 

 

 

* (1) - (3) ์˜ ํ•จ์ˆ˜๋Š” ์•ž๊ณผ ๋™์ผํ•˜๋‹ค. 

 

(1) ๊ตญ๊ฐ€๋ณ„ CSV ํŒŒ์ผ ์ €์žฅ 

def save_csv(data, filename):
    # ์ตœ์ข… ๊ฒฝ๋กœ ์ƒ์„ฑ 
    path = os.path.join(DEST_DIR, filename)

    with open(path, 'w', newline="") as fp:
        writer = csv.DictWriter(fp, fieldnames=HEADER)
        # Header Write
        writer.writeheader()
        # Dict to CSV write
        for row in data: 
            writer.writerow(row)

(2) ๊ตญ๊ฐ€๋ณ„ ๋ถ„๋ฆฌ

def get_sales_data(nt):
    with open(TARGET_CSV, 'r') as f:
        reader = csv.DictReader(f)
        # Dict๋ฅผ ๋ฆฌ์ŠคํŠธ๋กœ ์ ์žฌ 
        data = []
        # Header ํ™•์ธ 
        # print(reader.fieldnames)
        for r in reader:
            # OrderedDict ํ™•์ธ 
            # print(r)
            # ์กฐ๊ฑด์— ๋งž๋Š” ๊ตญ๊ฐ€๋งŒ ์‚ฝ์ž… 
            if r['Country'] == nt:
                data.append(r)
    return data

(3) ์ค‘๊ฐ„ ์ƒํ™ฉ ์ถœ๋ ฅ

def show(text):
    print(text, end=' ')
    # ์ค‘๊ฐ„ ์ถœ๋ ฅ (๋ฒ„ํผ ๋น„์šฐ๊ธฐ)
    sys.stdout.flush()

 

 

(4) ๊ตญ๊ฐ€ ๋ณ„ ๋ถ„๋ฆฌ ํ•จ์ˆ˜ ์‹คํ–‰ - (1) , (2) , (3) ํ•จ์ˆ˜ ์‚ฌ์šฉ

def separate_many(nt):
    # ๋ถ„๋ฆฌ ๋ฐ์ดํ„ฐ 
    data = get_sales_data(nt)
    # ์ƒํ™ฉ ์ถœ๋ ฅ 
    show(nt)
    # ํŒŒ์ผ ์ €์žฅ 
    save_csv(data, nt.lower() + '.csv')

    return nt

1๋ฒˆ ๋ฐฉ๋ฒ•์ธ ์ˆœ์ฐจ์‹คํ–‰์—์„œ๋Š” for๋ฌธ์„ ์ด์šฉํ•˜์—ฌ ๊ตญ๊ฐ€๋ณ„ csvํŒŒ์ผ์„ ๋งŒ๋“ค์–ด๋ƒˆ๋‹ค. 2๋ฒˆ ๋ฐฉ๋ฒ•์—์„œ๋Š” mapํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตญ๊ฐ€ ์ด๋ฆ„ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ›์ง€ ์•Š๊ณ  , ๊ตญ๊ฐ€์ด๋ฆ„ ํ•˜๋‚˜์”ฉ์„ ๋ฐ›์•„ csvํŒŒ์ผ๋กœ ์ €์žฅํ•œ๋‹ค.  ์ตœ์ข…์ ์œผ๋กœ ๊ตญ๊ฐ€์ด๋ฆ„ ํ•˜๋‚˜(nt)๋ฅผ ๋ฆฌํ„ดํ•˜๋„๋ก ๋งŒ๋“ ๋‹ค.

 

 

 

(5) ์‹œ๊ฐ„ ์ธก์ • ๋ฐ ๋ฉ”์ธ ํ•จ์ˆ˜

futures.ThreadPoolExecutor() / futures.ProcessPoolExecutor 

 

 - ThreadPoolExecutor : GIL ์ข…์† 

def main(separate_many):
    # worker ๊ฐœ์ˆ˜
    worker = min(20, len(NATION_LS))
    # ์‹œ์ž‘ ์‹œ๊ฐ„
    start_tm = time.time()
    # ๊ฒฐ๊ณผ ๊ฑด์ˆ˜
    with futures.ThreadPoolExecutor(worker) as excutor:
        # map -> ์ž‘์—… ์ˆœ์„œ ์œ ์ง€, ์ฆ‰์‹œ ์‹คํ–‰
        result = excutor.map(separate_many, sorted(NATION_LS))
    # ์ข…๋ฃŒ ์‹œ๊ฐ„
    end_tm = time.time() - start_tm

    msg = '\n{} csv separated in {:.2f}s'
    # ์ตœ์ข… ๊ฒฐ๊ณผ ์ถœ๋ ฅ
    print(msg.format(len(list(result)), end_tm))
    
    
# ์‹คํ–‰
if __name__ == '__main__':
    main(separate_many)

 France Norway Spain Germany Maxico Canada Singapore Israel Italy 
 9 csv separated in 21.61s 

worker ๋ผ๋Š” ์ผ๊พผ ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ๊ณ , ThreadPoolExecutor()์˜ ์ธ์ž์— ๋„ฃ์–ด์ค€๋‹ค. ์—ฌ๊ธฐ์„œ result๋Š” ์ œ๋„ˆ๋ ˆ์ดํ„ฐ ๊ฐ์ฒด๋กœ ์ €์žฅ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ์ตœ์ข…๊ฒฐ๊ณผ ์ถœ๋ ฅ์—์„œ ๋ฆฌ์ŠคํŠธ์˜ ๊ธธ์ด๋ฅผ ์•Œ๊ธฐ ์œ„ํ•ด result๋ฅผ list ํƒ€์ž…์œผ๋กœ ๋ฐ”๊ฟ”์ฃผ์–ด์•ผ ํ•œ๋‹ค. 

 

๋งŒ์•ฝ ๊ทธ๋ƒฅ len(result)๋กœ ์ž‘์„ฑํ•œ๋‹ค๋ฉด !

 File "c:/Users/./Desktop/python_high/chapter06_03_02.py", line 100, in main  
    result_cnt = len(excutor.map(separate_many, sorted(NATION_LS))) 
 TypeError: object of type 'generator' has no len() 

์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋Š” len() ๋ฅผ ๊ฐ–์ง€ ์•Š๋Š”๋‹ค๋Š” ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. 

 

 

 

 

- ProcessPoolExecutor : GIL ์šฐํšŒ, ๋ณ€๊ฒฝ ํ›„ -> ๋‚ด๋ถ€์ ์œผ๋กœ os.cpu_count() ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ (์šด์˜์ฒด์ œ ์ž์ฒด์—์„œ ์šฐํšŒ์—์„œ ๊ฐ -> ์†๋„๊ฐ€ ๋น ๋ฆ„ )

def main(separate_many):
    # worker ๊ฐœ์ˆ˜
    worker = min(20, len(NATION_LS))
    # ์‹œ์ž‘ ์‹œ๊ฐ„
    start_tm = time.time()
    # ๊ฒฐ๊ณผ ๊ฑด์ˆ˜
    with futures.ProcessPoolExecutor() as excutor:
        # map -> ์ž‘์—… ์ˆœ์„œ ์œ ์ง€, ์ฆ‰์‹œ ์‹คํ–‰
        result = excutor.map(separate_many, sorted(NATION_LS))
    # ์ข…๋ฃŒ ์‹œ๊ฐ„
    end_tm = time.time() - start_tm

    msg = '\n{} csv separated in {:.2f}s'
    # ์ตœ์ข… ๊ฒฐ๊ณผ ์ถœ๋ ฅ
    print(msg.format(len(list(result)), end_tm))
    
  
# ์‹คํ–‰
if __name__ == '__main__':
    main(separate_many)

 Norway Canada Germany France Spain Singapore Italy Maxico Israel 
 9 csv separated in 8.11s 

๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ ProcessPoolExecutor๋ฅผ ํ•ด๋ณธ๋‹ค. ์‹œ๊ฐ„์ด ํ›จ์”ฌ ๋‹จ์ถ•๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. 

 

์–ธ์ œ ProcessPoolExecutor์“ฐ๊ณ , ThreadPoolExecutor์“ฐ๊ณ , ์ฝ”๋ฃจํ‹ด์„ ์“ฐ๋Š”์ง€๋ฅผ ์ƒ๊ฐํ•ด์•ผ ํ•œ๋‹ค. ProcessPoolExecutor์“ฐ๋ฉด cpu ์‚ฌ์šฉ๋Ÿ‰์ด ๊ธ‰๊ฒฉํžˆ ์ฆ๊ฐ€ํ•˜๊ณ  ๋น ๋ฅธ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜จ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋Ÿฌํ•œ ๋ฉ€ํ‹ฐ ํ”„๋กœ์„ธ์‹ฑ์€ ๋‹จ๊ธฐ๊ฐ„์˜ ๋”ฅ๋Ÿฌ๋‹ ๊ณ ์† ์—ฐ์‚ฐ์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ThreadPoolExecutor์‚ฌ์šฉํ•˜๋ฉด ์†๋„๋Š” ๋” ๊ฑธ๋ฆฌ์ง€๋งŒ cpu ์‚ฌ์šฉ๋Ÿ‰์€ ์ž”์ž”ํ•˜๊ฒŒ ์ฆ๊ฐ€ํ•œ๋‹ค. ์ด ๋‘๊ฐ€์ง€์˜ ์ฐจ์ด๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ณ  , ์ ์ ˆํžˆ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. 

 

 

 

 

 

 

 

 

- 3. concurrent.futures ๋ฐฉ๋ฒ•2 (map()ํ•จ์ˆ˜ ๋Œ€์‹  for๋ฌธ์„ ์ด์šฉํ•˜์—ฌ ์„ธ๋ถ€์ ์ธ ๊ณผ์ • ์ฐ์–ด๋ณด๊ธฐ) 

 

* (1) - (3) ์˜ ํ•จ์ˆ˜๋Š” ์•ž๊ณผ ๋™์ผํ•˜๋‹ค. 

 

(4) ๊ตญ๊ฐ€ ๋ณ„ ๋ถ„๋ฆฌ ํ•จ์ˆ˜ ์‹คํ–‰ - (1) , (2) , (3) ํ•จ์ˆ˜ ์‚ฌ์šฉ

def main(separate_many):
    # worker ๊ฐœ์ˆ˜
    worker = min(20, len(NATION_LS))
    # ์‹œ์ž‘ ์‹œ๊ฐ„
    start_tm = time.time()
    # futures 
    futures_list = []
    # ๊ฒฐ๊ณผ ๊ฑด์ˆ˜
    # ProcessPoolExecutor : GIL ์šฐํšŒ, ๋ณ€๊ฒฝ ํ›„ -> ๋‚ด๋ถ€์ ์œผ๋กœ os.cpu_count() ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ (์šด์˜์ฒด์ œ ์ž์ฒด์—์„œ ์šฐํšŒ์—์„œ ๊ฐ)
    # ThreadPoolExecutor : GIL ์ข…์† 
    # with futures.ThreadPoolExecutor(worker) as excutor:
    with futures.ProcessPoolExecutor() as excutor:
        # submit -> callable ๊ฐ์ฒด ์Šค์ผ€์ฅด๋ง(์‹คํ–‰ ์˜ˆ์•ฝ) -> future 
        # Future -> as_complete(), result(), done(), cancelled() ์ฃผ๋กœ ์‚ฌ์šฉ 
        for nt in sorted(NATION_LS):
            # future ๋ฐ˜ํ™˜
            future = excutor.submit(separate_many, nt)
            # ์Šค์ผ€์ฅด๋ง
            futures_list.append(future)
            # ์ถœ๋ ฅ 
            # print('Scheduled for {} : {}'.format(nt, future))
            # print()

        for future in futures.as_completed(futures_list):
            result = future.result()
            done = future.done()
            cancelled = future.cancelled()
            # furue ๊ฒฐ๊ณผ ํ™•์ธ 
            print('Future Result : {}, Done : {}'.format(result, done))
            print('Future Cancelled : {}'.format(cancelled))

    # ์ข…๋ฃŒ ์‹œ๊ฐ„
    end_tm = time.time() - start_tm

    msg = '\n{} csv separated in {:.2f}s'
    # ์ตœ์ข… ๊ฒฐ๊ณผ ์ถœ๋ ฅ
    print(msg.format(len(futures_list), end_tm))

for๋ฌธ์œผ๋กœ ์ž‘์—…์„ ์ผ์ผ์ด ํ•˜๊ณ , ์„ธ๋ถ€์ ์œผ๋กœ ์ง„ํ–‰์ƒํ™ฉ๊ณผ ์–ด๋–ป๊ฒŒ ๋งˆ๋ฌด๋ฆฌ ๋˜์—ˆ๋Š”์ง€๋ฅผ ์•Œ๊ณ  ์‹ถ์„ ๋•Œ ์ด ๋ฐฉ๋ฒ•์„ ์“ด๋‹ค. 

2๋ฒˆ ๋ฐฉ๋ฒ•์—์„œ๋Š” map()ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ separate_many ํ•จ์ˆ˜๋กœ ๊ตญ๊ฐ€๋ณ„ csvํŒŒ์ผ์„ ์ €์žฅํ•ด ์ฃผ์—ˆ๋‹ค. 3๋ฒˆ ๋ฐฉ๋ฒ•์—์„œ๋Š” submit()ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ futre๋ณ€์ˆ˜์— ํ• ๋‹นํ•ด์ฃผ๊ณ  , ์ด future๋ฅผ futures_list์— append ํ•ด์ค€๋‹ค. 

 

futures.as_complted()์˜ ์ธ์ž์— futures_list๋ฅผ ๋„ฃ์–ด์ฃผ๊ณ , ๊ฐ๊ฐ์˜ future์— ๋Œ€ํ•œ result, done, cancelled ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. 

 

 

* ์‹คํ–‰ 

if __name__ == '__main__':
    main(separate_many)

 Germany Canada Future Result : Germany, Done : True 
 Future Cancelled : False 
 Norway Israel Future Result : Norway, Done : True 
 Italy Future Cancelled : False 
 Future Result : Canada, Done : True 
 Future Cancelled : False 
 Future Result : Israel, Done : True 
 Future Cancelled : False 
 Future Result : Italy, Done : True 
 Future Cancelled : False 
 Singapore France Future Result : Singapore, Done : True 
 Future Cancelled : False 
 Future Result : France, Done : True 
 Future Cancelled : False 
 Maxico Future Result : Maxico, Done : True 
 Future Cancelled : False 
 Spain Future Result : Spain, Done : True 
 Future Cancelled : False 

 9 csv separated in 8.60s 

์‹คํ–‰์„ ํ•ด๋ณด๋ฉด , result๋Š” ๊ฐ ๊ตญ๊ฐ€์˜ ์ด๋ฆ„(nt : separate_many์˜ ๋ฆฌํ„ด๊ฐ’), Done์€ ๋ชจ๋‘ True, Cancelled๋Š” ๋ชจ๋‘ False๊ฐ€ ๋‚˜์™€ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™ํ•œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์ด์™€ ๊ฐ™์ด for๋ฌธ๊ณผ submitํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ธ๋ถ€์ ์ธ ๋‚ด์šฉ์„ ํ™•์ธํ•  ์ˆ˜๋„ ์žˆ๋‹ค. 

+ Recent posts