1. 程式人生 > >python之並發編程

python之並發編程

eoq mar reat 文件中 install adt obj fff stdout

一 背景知識

顧名思義,進程即正在執行的一個過程。進程是對正在運行程序的一個抽象。

進程的概念起源於操作系統,是操作系統最核心的概念,也是操作系統提供的最古老也是最重要的抽象概念之一。操作系統的其他所有內容都是圍繞進程的概念展開的。

所以想要真正了解進程,必須事先了解操作系統,點擊進入

PS:即使可以利用的cpu只有一個(早期的計算機確實如此),也能保證支持(偽)並發的能力。將一個單獨的cpu變成多個虛擬的cpu(多道技術:時間多路復用和空間多路復用+硬件上支持隔離),沒有進程的抽象,現代計算機將不復存在。

必備的理論基礎:

技術分享圖片
#一 操作系統的作用:
    1:隱藏醜陋復雜的硬件接口,提供良好的抽象接口
    
2:管理、調度進程,並且將多個進程對硬件的競爭變得有序 #二 多道技術: 1.產生背景:針對單核,實現並發 ps: 現在的主機一般是多核,那麽每個核都會利用多道技術 有4個cpu,運行於cpu1的某個程序遇到io阻塞,會等到io結束再重新調度,會被調度到4個 cpu中的任意一個,具體由操作系統調度算法決定。 2.空間上的復用:如內存中同時有多道程序 3.時間上的復用:復用一個cpu的時間片 強調:遇到io切,占用cpu時間過長也切,核心在於切之前將進程的狀態保存下來,這樣 才能保證下次切換回來時,能基於上次切走的位置繼續運行
技術分享圖片

本文將將著重介紹進程以及它的親戚->線程

二 python並發編程之多進程

理論:http://www.cnblogs.com/linhaifeng/articles/7430066.html

鏈接:http://www.cnblogs.com/linhaifeng/articles/7428874.html

三 python並發編程之多線程

理論:http://www.cnblogs.com/linhaifeng/articles/7430082.html

鏈接:http://www.cnblogs.com/linhaifeng/articles/7428877.html

四 python並發編程之協程

鏈接:http://www.cnblogs.com/linhaifeng/articles/7429894.html

五 python並發編程之IO模型

鏈接:http://www.cnblogs.com/linhaifeng/articles/7454717.html

六 補充:paramiko模塊

1. 介紹:

paramiko是一個用於做遠程控制的模塊,使用該模塊可以對遠程服務器進行命令或文件操作,值得一說的是,fabric和ansible內部的遠程管理就是使用的paramiko來現實。

2. 下載安裝

pip3 install paramiko #在python3中
技術分享圖片
pycrypto,由於 paramiko 模塊內部依賴pycrypto,所以先下載安裝pycrypto #在python2中
pip3 install pycrypto
pip3 install paramiko
註:如果在安裝pycrypto2.0.1時發生如下錯誤
        command gcc failed with exit status 1...
可能是缺少python-dev安裝包導致
如果gcc沒有安裝,請事先安裝gcc
在python2中

3. 使用

SSHClient

用於連接遠程服務器並執行基本命令

基於用戶名密碼連接:

技術分享圖片
import paramiko

# 創建SSH對象
ssh = paramiko.SSHClient()
# 允許連接不在know_hosts文件中的主機
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 連接服務器
ssh.connect(hostname=120.92.84.249, port=22, username=root, password=xxx)

# 執行命令
stdin, stdout, stderr = ssh.exec_command(df)
# 獲取命令結果
result = stdout.read()
print(result.decode(utf-8))
# 關閉連接
ssh.close()
技術分享圖片 技術分享圖片
import paramiko

transport = paramiko.Transport((120.92.84.249, 22))
transport.connect(username=root, password=xxx)

ssh = paramiko.SSHClient()
ssh._transport = transport

stdin, stdout, stderr = ssh.exec_command(df)
res=stdout.read()
print(res.decode(utf-8))

transport.close()
SSHClient 封裝 Transport

基於公鑰密鑰連接:

客戶端文件名:id_rsa

服務端必須有文件名:authorized_keys(在用ssh-keygen時,必須制作一個authorized_keys,可以用ssh-copy-id來制作)

技術分享圖片
import paramiko

private_key = paramiko.RSAKey.from_private_key_file(/tmp/id_rsa)

# 創建SSH對象
ssh = paramiko.SSHClient()
# 允許連接不在know_hosts文件中的主機
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 連接服務器
ssh.connect(hostname=120.92.84.249, port=22, username=root, pkey=private_key)

# 執行命令
stdin, stdout, stderr = ssh.exec_command(df)
# 獲取命令結果
result = stdout.read()
print(result.decode(utf-8))
# 關閉連接
ssh.close()
View Code 技術分享圖片
import paramiko

private_key = paramiko.RSAKey.from_private_key_file(/tmp/id_rsa)

transport = paramiko.Transport((120.92.84.249, 22))
transport.connect(username=root, pkey=private_key)

ssh = paramiko.SSHClient()
ssh._transport = transport

stdin, stdout, stderr = ssh.exec_command(df)
result=stdout.read()
print(result.decode(utf-8))

transport.close()
SSHClient 封裝 Transport 技術分享圖片
import paramiko
from io import StringIO

key_str = """-----BEGIN RSA PRIVATE KEY-----
MIIEoQIBAAKCAQEAsJmFLrSeCumJvga0Gl5O5wVOVwMIy2MpqIyQPi5J87dg89a4
Da9fczJog7qoSbRwHFOQoCHNphSlp5KPhGsF6RJewkIw9H1UKV4dCOyl/4HOAkAD
rKrsEDmrJ9JlzF2GTTZSnTgVQWcvBS2RKB4eM2R9aJ11xV6X2Hk4YDLTExIWeabb
h2TUKw0iyjI8pRuYLKkF2X16u9TBwfOTroGYgiNFHQvhsQppbEbI49NF2XkCkFMi
8/7tLjf95InE/VUUq56JqfzyHwdpHou+waXbwtvGgXN3sz+KkuEv6R2qDz06upZV
FCZRRpDhzoR8Uh/UEzTGZb8z7FB6EJXUiXJikQIBIwKCAQBBmBuGYFf1bK+BGG7H
9ySe81ecqVsJtx4aCFLVRGScWg4RbQKIvXs5an6XU/VdNGQnx0RYvBkvDvuzRRC8
J8Bd4kB0CfTtGJuaVigKoQp02HEWx1HSa17+tlWD0c4KFBvwywi+DYQ83S64x8gz
eOalX9bPFenqORPUD8R7gJeKvPVc6ZTPeorpuH7u9xayP0Eop8qKxZza9Xh3foVj
Qo4IxoYnDN57CIRX5PFSlDDggpmr8FtRF4nAxmFq8LhSp05ivzX/Ku1SNHdaMWZO
7va8tISXdLI5m0EGzoVoBvohIbwlxI6kfmamrh6Eas2Jnsc4CLzMsR4jBWt0LHLv
/SLnAoGBANaEUf/Jptab9G/xD9W2tw/636i3gLpTPY9KPtCcAxqStNeT6RAWZ5HF
lKJg+NKpu3pI45ldAwvts0i+aCZk2xakEWIZWqCmXm31JSPDQTaMGe7H0vOmUaxx
ncdpBVdvhMbfFUgei15iKfuafgrKaS9oIkntXEgrC+3wBOI0Gbx3AoGBANLAGxAF
TK7ydr+Q1+6/ujs6e8WsXt8HZMa/1khCVSbrf1MgACvZPSSSrDpVwaDTSjlRI4AL
bb0l0RFU+/0caMiHilscuJdz9Fdd9Ux4pjROZa3TF5CFhvP7PsZAoxOo+yqJg4zr
996GG/aAv4M8lQJ2rDFk/Dgn5y/AaAun1oM3AoGAGIQmoOPYjY4qkHNSRE9lYOl4
pZFQilKn8x5tlC8WTC4GCgJGhX7nQ9wQ/J1eQ/YkDfmznH+ok6YjHkGlgLsRuXHW
GdcDCwuzBUCWh76LHC1EytUCKnloa3qy8jfjWnMlHgrd3FtDILrC+C7p1Vj2FAvm
qVz0moiTpioPL8twp9MCgYEAin49q3EyZFYwxwdpU7/SJuvq750oZq0WVriUINsi
A6IR14oOvbqkhb94fhsY12ZGt/N9uosq22H+anms6CicoQicv4fnBHDFI3hCHE9I
pgeh50GTJHUA6Xk34V2s/kp5KpThazv6qCw+QubkQExh660SEdSlvoCfPKMCi1EJ
TukCgYAZKY1NZ2bjJyyO/dfNvMQ+etUL/9esi+40GUGyJ7SZcazrN9z+DO0yL39g
7FT9NMIc2dsmNJQMaGBCDl0AjO1O3b/wqlrNvNBGkanxn2Htn5ajfo+LBU7yHAcV
7w4X5HLarXiE1mj0LXFKJhdvFqU53KUQJXBqR6lsMqzsdPwLMJg==
-----END RSA PRIVATE KEY-----"""

private_key = paramiko.RSAKey(file_obj=StringIO(key_str))
transport = paramiko.Transport((120.92.84.249, 22))
transport.connect(username=root, pkey=private_key)

ssh = paramiko.SSHClient()
ssh._transport = transport

stdin, stdout, stderr = ssh.exec_command(df)
result = stdout.read()
print(result.decode(utf-8))
transport.close()

print(result)
基於私鑰字符串進行連接

SFTPClient

用於連接遠程服務器並執行上傳下載

基於用戶名密碼上傳下載

技術分享圖片
import paramiko
 
transport = paramiko.Transport((120.92.84.249,22))
transport.connect(username=root,password=xxx)
 
sftp = paramiko.SFTPClient.from_transport(transport)
# 將location.py 上傳至服務器 /tmp/test.py
sftp.put(/tmp/id_rsa, /etc/test.rsa)
# 將remove_path 下載到本地 local_path
sftp.get(remove_path, local_path)
 
transport.close()
View Code

基於公鑰密鑰上傳下載

技術分享圖片
import paramiko

private_key = paramiko.RSAKey.from_private_key_file(/tmp/id_rsa)

transport = paramiko.Transport((120.92.84.249, 22))
transport.connect(username=root, pkey=private_key )

sftp = paramiko.SFTPClient.from_transport(transport)
# 將location.py 上傳至服務器 /tmp/test.py
sftp.put(/tmp/id_rsa, /tmp/a.txt)
# 將remove_path 下載到本地 local_path
sftp.get(remove_path, local_path)

transport.close()
View Code 技術分享圖片
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import paramiko
import uuid

class Haproxy(object):

    def __init__(self):
        self.host = 172.16.103.191
        self.port = 22
        self.username = root
        self.pwd = 123
        self.__k = None

    def create_file(self):
        file_name = str(uuid.uuid4())
        with open(file_name,w) as f:
            f.write(sb)
        return file_name

    def run(self):
        self.connect()
        self.upload()
        self.rename()
        self.close()

    def connect(self):
        transport = paramiko.Transport((self.host,self.port))
        transport.connect(username=self.username,password=self.pwd)
        self.__transport = transport

    def close(self):

        self.__transport.close()

    def upload(self):
        # 連接,上傳
        file_name = self.create_file()

        sftp = paramiko.SFTPClient.from_transport(self.__transport)
        # 將location.py 上傳至服務器 /tmp/test.py
        sftp.put(file_name, /home/root/tttttttttttt.py)

    def rename(self):

        ssh = paramiko.SSHClient()
        ssh._transport = self.__transport
        # 執行命令
        stdin, stdout, stderr = ssh.exec_command(mv /home/root/tttttttttttt.py /home/root/ooooooooo.py)
        # 獲取命令結果
        result = stdout.read()


ha = Haproxy()
ha.run()
Demo

七 作業

題目:簡單主機批量管理工具

需求:

  1. 主機分組
  2. 主機信息配置文件用configparser解析
  3. 可批量執行命令、發送文件,結果實時返回,執行格式如下
    1. batch_run -h h1,h2,h3 -g web_clusters,db_servers -cmd "df -h" 
    2. batch_scp -h h1,h2,h3 -g web_clusters,db_servers -action put -local test.py -remote /tmp/ 
  4. 主機用戶名密碼、端口可以不同
  5. 執行遠程命令使用paramiko模塊
  6. 批量命令需使用multiprocessing並發

python之並發編程