python 학습일기-2016.7.25

10938 단어

1. 다중 프로세스


멀티프로세스 모듈은 크로스플랫폼 버전의 다중 프로세스 모듈입니다.multiprocessing 모듈은 프로세스 대상을 대표하는 Process 클래스를 제공합니다. 다음 예는 하위 프로세스를 시작하고 끝날 때까지 기다리는 것을 보여 줍니다.
from multiprocessing import Process
import os
#          
def run_proc(name): 
  print('Run child process %s (%s)...' % (name, os.getpid()))
if __name__=='__main__': 
  print('Parent process %s.' % os.getpid()) 
  p = Process(target=run_proc, args=('test',)) 
  print('Child process will start.') 
  p.start() 
  p.join() 
  print('Child process end.')

실행 결과는 다음과 같습니다.
Parent process 10960
child process will start
run process test (7448)...
child process end

하위 프로세스를 만들 때 실행 함수와 함수의 매개 변수를 입력하고 Process 실례를 만들고 start () 방법으로 시작하면 프로세스가 fork () 보다 간단합니다.
join () 방법은 하위 프로세스가 끝난 후에 계속 아래로 실행할 수 있으며, 보통 프로세스 간의 동기화에 사용됩니다.많은 수의 하위 프로세스를 시작하는 경우 프로세스 풀을 사용하여 하위 프로세스를 대량 생성할 수 있습니다.

2. 프로세스 풀

from multiprocessing 
import Poolimport os, time, random
def a(name):    
  print('run task %s (%s)' %(name,os.getpid()))    
  start=time.time()    
  time.sleep(random.random()*3)    
  end=time.time()    
  print('task %s runs %0.2f seconds' %(name,(end-start)))

if __name__=='__main__':    
  print('parent process %s' %os.getpid())    
  p=Pool(4)    
  for i in range(5):        
    p.apply_async(a, args=(i,))    
    print('wait for all subprocessed done')    
    p.close()    
    p.join()    
    print('all subprocess done')

결과는 다음과 같습니다.
parent process 9404
wait for all subprocessed done
run task 0 (4896)
run task 1 (1964)
run task 2 (2296)
run task 3 (11092)
task 1 runs 0.59 seconds
run task 4 (1964)
task 4 runs 1.08 seconds
task 2 runs 2.25 seconds
task 3 runs 2.78 seconds
task 0 runs 2.97 seconds
all subprocess done

코드 판독: Pool 대상에 대해join () 방법을 호출하면 모든 하위 프로세스가 실행될 때까지 기다립니다.join () 을 호출하기 전에 close () 를 호출해야 합니다.close () 를 호출한 후에 새로운 Process를 추가할 수 없습니다.출력 결과에 주의하십시오.task0, 1, 2, 3은 즉시 실행됩니다.task4는 앞에 있는task가 완성된 후에 실행됩니다. 이것은 Pool의 기본 크기가 제 컴퓨터에서 4이기 때문에 최대 4개의 프로세스를 동시에 실행합니다.이것은 Pool이 의도적으로 설계한 제한이지 운영체제의 제한이 아니다.만약 p=Pool(5)로 바꾸면 다섯 개의 프로세스를 동시에 뛸 수 있다.Pool의 기본 크기는 CPU의 핵 수이기 때문에, 만약 불행하게도 8핵 CPU를 가지고 있다면, 최소한 9개의 하위 프로세스를 제출해야만 위의 대기 효과를 볼 수 있습니다.

3. 하위 프로세스


하위 프로세스는 자신이 아니라 외부 프로세스일 때가 많다.하위 프로세스를 만든 후에 하위 프로세스의 입력과 출력을 제어해야 합니다.subprocess 모듈은 하위 프로세스를 쉽게 시작하고 입력과 출력을 제어할 수 있습니다.다음 예는 Python 코드에서 명령 nslookup www.python을 실행하는 방법을 보여 줍니다.org, 이것은 명령줄이 직접 실행되는 것과 같은 효과입니다.
import subprocess
print('$ nslookup www.python.org')
r = subprocess.call(['nslookup', 'www.python.org'])print('Exit code:', r)

실행 결과:
$ nslookup www.python.org
Server: 192.168.19.4
Address: 192.168.19.4#53

Non-authoritative answer:
www.python.org canonical name = python.map.fastly.net.
Name: python.map.fastly.net
Address: 199.27.79.223
Exit code: 0

하위 프로세스를 더 입력해야 하는 경우 communicate () 방법으로 다음을 입력할 수 있습니다.
import subprocess
print('$ nslookup')
p = subprocess.Popen(['nslookup'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, err = p.communicate(b'set q=mx
python.org
exit
') print(output.decode('utf-8')) print('Exit code:', p.returncode)

위의 코드는 명령줄에서 nslookup 명령을 실행하고 수동으로 입력하는 것과 같습니다: set q=mx python.org exit
실행 결과는 다음과 같습니다.
$ nslookup
Traceback (most recent call last):
  File "E:/intelliJProject/firstpython/b.py", line 7, in 
    print(output.decode('utf-8'))
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc8 in position 2: invalid continuation byte


결과 오류가 발생했습니다.utf-8을 사용할 수 없습니다.gbk로 바꾸고 실행하면 됩니다
$ nslookup
     :  UnKnown
Address:  172.20.1.4

> >    :  UnKnown
Address:  172.20.1.4

python.org  MX preference = 50, mail exchanger = mail.python.org

python.org  nameserver = ns3.p11.dynect.net
python.org  nameserver = ns4.p11.dynect.net
python.org  nameserver = ns1.p11.dynect.net
python.org  nameserver = ns2.p11.dynect.net
mail.python.org internet address = 188.166.95.178
mail.python.org AAAA IPv6 address = 2a03:b0c0:2:d0::71:1
ns1.p11.dynect.net  internet address = 208.78.70.11
ns2.p11.dynect.net  internet address = 204.13.250.11
ns3.p11.dynect.net  internet address = 208.78.71.11
ns4.p11.dynect.net  internet address = 204.13.251.11
> 
Exit code: 0

4. 프로세스 간 통신


Process 간에 통신이 필요할 것이다. 운영체제는 프로세스 간의 통신을 실현하기 위해 많은 메커니즘을 제공했다.파이톤의 멀티프로세싱 모듈은 밑바닥의 메커니즘을 포장하고 Queue, Pipes 등 다양한 방식으로 데이터를 교환한다.
Queue를 예로 들면 상위 프로세스에서 두 개의 하위 프로세스를 만듭니다. 하나는 Queue에 데이터를 쓰고 하나는 Queue에서 데이터를 읽습니다.
#-*- coding=utf-8 -*-
from multiprocessing import Process,Queue
import os,time,random
def write(q):    
  print('process to write:%s' %os.getpid())    
  for value in ['A','B','C']:        
    print('put %s to queue...'%value)        
    q.put(value)        
    time.sleep(random.random())

def read(q):    
  print('process to read:%s' %os.getpid())    
  while(True):        
    value=q.get(True)        
    print('get %s frome queue...' %value)

if __name__=='__main__':    
  q=Queue()    
  pw=Process(target=write, args=(q,))    
  pr=Process(target=read, args=(q,))    
  pw.start()    
  pr.start()    
  pw.join()    
  pr.terminate()

실행 결과:
process to write:9980
put A to queue...
process to read:6424
get A frome queue...
put B to queue...
get B frome queue...
put C to queue...
get C frome queue...

5. 다중 스레드


다중 임무는 다중 프로세스로 완성할 수도 있고, 한 프로세스 내의 다중 프로세스로 완성할 수도 있다.앞에서 언급한 바와 같이 프로세스는 몇 개의 라인으로 구성되어 있으며, 한 프로세스는 적어도 하나의 라인이 있다.루틴은 운영체제가 직접 지원하는 실행 단원이기 때문에 고급 언어는 보통 다중 루틴 지원을 내장하고 Python도 예외가 아니다. 또한 Python의 루틴은 아날로그된 루틴이 아니라 진정한 Posix Thread이다.Python의 표준 라이브러리는 두 개의 모듈을 제공합니다:thread와 threading,thread는 저급 모듈,threading은 고급 모듈,맞아thread가 봉인되었습니다.절대 다수의 상황에서 우리는threading이라는 고급 모듈만 사용할 수 있다.스레드를 시작하면 함수를 가져와 Thread 인스턴스를 만들고 start () 를 호출하여 실행합니다.
import time, threading
#         :
def loop(): 
  print('thread %s is running...' % threading.current_thread().name) 
  n = 0 
  while n < 5: 
    n = n + 1 
    print('thread %s >>> %s' % (threading.current_thread().name, n))
    time.sleep(1) 
print('thread %s ended.' % threading.current_thread().name)

print('thread %s is running...' % threading.current_thread().name)
t = threading.Thread(target=loop, name='LoopThread')
t.start()
t.join()
print('thread %s ended.' % threading.current_thread().name)

결과는 다음과 같습니다.
thread MainThread is running...
thread LoopThread is running...
thread LoopThread >>> 1
thread LoopThread >>> 2
thread LoopThread >>> 3
thread LoopThread >>> 4
thread LoopThread >>> 5t
hread LoopThread ended.
thread MainThread ended.

모든 프로세스가 기본적으로 하나의 라인을 시작하기 때문에, 우리는 이 라인을 주 라인이라고 부르고, 주 라인은 새로운 라인을 시작할 수 있습니다. Python의threading 모듈에currentthread () 함수, 현재 라인의 실례를 영원히 되돌려줍니다.주 스레드 실례의 이름은MainThread이고, 하위 스레드의 이름은 만들 때 지정되며, LoopThread로 하위 스레드를 명명합니다.이름은 인쇄할 때만 표시됩니다. 전혀 의미가 없습니다. 이름이 없으면 Python은 자동으로 라인에 Thread-1, Thread-2...

6. 스레드 잠금


다중 프로세스와 다중 프로세스의 가장 큰 차이점은 다중 프로세스에서 같은 변수는 각각 하나의 복사본이 모든 프로세스에 존재하고 서로 영향을 주지 않는다는 것이다. 그러나 다중 프로세스에서 모든 변수는 모든 프로세스가 공유하기 때문에 모든 변수는 하나의 프로세스에 의해 수정될 수 있다. 따라서 프로세스 간에 데이터를 공유하는 가장 큰 위험은 여러 프로세스가 동시에 변수를 바꾸어 내용을 어지럽히는 데 있다.여러 개의 라인이 하나의 변수를 동시에 조작하는데 어떻게 내용을 어지럽혔는지 살펴보자.
#-*- coding=utf-8 -*-
import time,threading
balance=0
def change_it(n):    
  global balance    
  balance+=n    
  balance-=n

def runthread(n):    
  for i in range(100000):
    change_it(n)

t1=threading.Thread(target=runthread, args=(5,))
t2=threading.Thread(target=runthread, args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)

실행할 때마다 결과가 달라요.
13
5
5
0
...

우리는 공유 변수balance를 정의했는데 초기 값이 0이고 두 개의 라인을 시작하여 먼저 저장하고 나중에 취한다. 이론적으로 결과는 0이어야 한다. 그러나 라인의 스케줄링은 운영체제에 의해 결정되기 때문에 t1, t2가 번갈아 실행할 때 순환 횟수가 충분하면 balance의 결과는 반드시 0이 아니다.왜냐하면 고급 언어의 한 문장이 CPU에서 실행될 때 몇 개의 문장이기 때문이다. 간단한 계산인 balance=balance+n도 두 단계로 나뉜다. balance+n을 계산하여 임시 변수에 저장한다.임시 변수의 값을 balance에 부여합니다.즉, x = balance + n balance = x
x는 부분적인 변수이기 때문에 두 스레드는 각각 자신의 x를 가지고 코드가 정상적으로 실행될 때:
    balance = 0
t1: x1 = balance + 5 # x1 = 0 + 5 = 5
t1: balance = x1 # balance = 5
t1: x1 = balance - 5 # x1 = 5 - 5 = 0
t1: balance = x1 # balance = 0
t2: x2 = balance + 8 # x2 = 0 + 8 = 8
t2: balance = x2 # balance = 8
t2: x2 = balance - 8 # x2 = 8 - 8 = 0
t2: balance = x2 # balance = 0
   balance = 0

그러나 t1과 t2는 번갈아 운행한다. 만약 운영체제가 아래의 순서로 t1, t2를 실행한다면
    balance = 0
t1: x1 = balance + 5 # x1 = 0 + 5 = 5
t2: x2 = balance + 8 # x2 = 0 + 8 = 8
t2: balance = x2 # balance = 8
t1: balance = x1 # balance = 5
t1: x1 = balance - 5 # x1 = 5 - 5 = 0
t1: balance = x1 # balance = 0
t2: x2 = balance - 8 # x2 = 0 - 8 = -8
t2: balance = x2 # balance = -8
   balance = -8

그 이유는 balance를 수정하는 데 여러 개의 문장이 필요하기 때문에 이 몇 개의 문장을 실행할 때 노선이 중단될 수 있기 때문에 여러 개의 노선이 같은 대상의 내용을 어지럽힐 수 있기 때문이다.두 라인을 동시에 예금하면 잔액이 틀릴 수 있습니다. 당신은 틀림없이 당신의 은행 예금이 영문도 모른 채 마이너스로 변하는 것을 원하지 않을 것입니다. 그래서 우리는 한 라인이 balance를 수정할 때 다른 라인은 반드시 바꿀 수 없도록 확보해야 합니다.만약 우리가 balance 계산이 정확하다는 것을 확보하려면changeit () 이전 자물쇠, 어떤 라인이change를 실행하기 시작하면it () 시, 이 스레드는 자물쇠를 얻었기 때문에 다른 스레드는change 를 동시에 실행할 수 없습니다.it (), 자물쇠가 풀릴 때까지 기다릴 수 있으며, 이 자물쇠를 얻은 후에야 변경할 수 있습니다.자물쇠가 하나밖에 없기 때문에 아무리 라인이 많더라도 같은 시간에 최대 한 라인만 이 자물쇠를 가지고 있기 때문에 수정된 충돌을 일으키지 않습니다.자물쇠를 만들면threading을 통과합니다.Lock()을 사용하여 다음을 수행할 수 있습니다.
balance = 0
lock = threading.Lock()
def run_thread(n): 
  for i in range(100000): 
    #      : 
    lock.acquire() 
    try: 
    #      : 
      change_it(n) 
    finally: 
      #          : 
      lock.release()

여러 라인이 동시에 lock을 실행합니다.acquire () 에서는 자물쇠를 성공적으로 가져온 다음 코드를 계속 실행하고, 다른 루트는 자물쇠를 얻을 때까지 기다립니다.자물쇠를 얻은 라인을 다 사용한 후에 반드시 자물쇠를 풀어야 한다. 그렇지 않으면 자물쇠를 기다리는 라인은 영원히 기다리며 죽은 라인이 될 것이다.그래서 저희가 try로...자물쇠가 반드시 풀릴 수 있도록 finally를 확보하세요.자물쇠의 장점은 특정한 관건적인 코드가 한 라인에서만 처음부터 끝까지 완전하게 집행될 수 있다는 것을 확보하는 것이다. 나쁜 점도 당연히 많다. 우선 여러 라인이 동시에 집행되는 것을 막는다. 자물쇠를 포함하는 특정한 코드는 사실상 단일 라인 모델로만 집행할 수 있고 효율이 크게 떨어진다.그 다음으로 여러 개의 자물쇠가 존재할 수 있기 때문에 서로 다른 라인이 서로 다른 자물쇠를 가지고 상대방이 가지고 있는 자물쇠를 얻으려고 할 때 사라진 자물쇠를 초래하여 여러 라인이 모두 걸려 있고 실행할 수도 없고 끝낼 수도 없으며 운영체제에 의해 강제로 종료될 수 있다.

7.ThreadLocal


ThreadLocal 변수는 전역 변수이지만, 모든 스레드는 자신의 스레드의 독립된 복사본만 읽을 수 있고, 서로 간섭하지 않는다.ThreadLocal은 매개변수가 스레드의 각 함수 간에 서로 전달되는 문제를 해결합니다.

8.정규 표현식


참조 정규 표현식

좋은 웹페이지 즐겨찾기