ホームページ  >  記事  >  バックエンド開発  >  サブプロセスを利用してパイプラインパイプ対話操作の読み書き通信方式を実現するPython3の詳細解説

サブプロセスを利用してパイプラインパイプ対話操作の読み書き通信方式を実現するPython3の詳細解説

高洛峰
高洛峰オリジナル
2017-03-20 10:28:124269ブラウズ

ここでは Windows のシェルを例として使用します:

 subprocess  *

理解を容易にするために、非常に単純なコードを使用して説明します:

サブプロセスを利用してパイプラインパイプ対話操作の読み書き通信方式を実現するPython3の詳細解説

Popen を使用して p をインスタンス化し、サブルーチンを作成していることがわかります。 . cmd.exe に、Stdin (標準入力ストリーム) と Stdout (標準出力ストリーム) を指定します。

は、これらのチャネルが開かれることを示すために使用される特別な値です。 。 (Python3.5 では、操作を改善するために run() メソッドが追加されました)

それでは続きます

サブプロセスを利用してパイプラインパイプ対話操作の読み書き通信方式を実現するPython3の詳細解説

この情報に見覚えはありますか?これは cmd の標準出力のすべてです。

すると、次のように出力されます:

サブプロセスを利用してパイプラインパイプ対話操作の読み書き通信方式を実現するPython3の詳細解説

先ほど書いたメッセージ「echo Hellwworldsrn」が書き込まれ、成功したようです。

入力バッファをリフレッシュするために p.stdin.flush() を使用することに注意してください。少なくとも Windows システムでは、出力情報にも "rn" が必要です。それ以外の場合は、リフレッシュ (p.stdin .flush) のみが無効になります。

具体的に何をしたのですか?


サブルーチン cmd.exe の作成に成功し、「echo Hellwworldsrn」を書き込みました。その後、cmd がそれを取得して実行し、Hellwworlds に戻りました。これは非常に単純な読み取り/書き込み操作です。

より高度な使用法

簡単に読み書きできるようになったので、for とスレッドを追加しましょう。味が良くなるかもしれません~

#run.py  

from subprocess import * 
import threading 
import time

p =Popen('cmd.exe',shell=True,stdin=PIPE,stdout=PIPE)

def run():
    global p
    while True:
        line = p.stdout.readline() 
        if not line:  #空则跳出
            break
        print(">>>>>>",line.decode("GBK"))

    print("look up!!! EXIT ===")   #跳出


w =threading.Thread(target=run)

p.stdin.write("echo HELLW_WORLD!\r\n".encode("GBK"))
p.stdin.flush()
time.sleep(1) #延迟是因为等待一下线程就绪
p.stdin.write("exit\r\n".encode("GBK"))
p.stdin.flush()

w.start()

とても良いですね、出力は何だと思いますか?

サブプロセスを利用してパイプラインパイプ対話操作の読み書き通信方式を実現するPython3の詳細解説

改行が多い理由は、cmdが返す結果に改行があり、印刷出力では改行が追加されるため、sys.stdoutの使用を検討できます。 .write を実行して、追加の行が入らないようにします

この場合、基本的な読み取りと書き込みができたら、カプセル化を開始しましょう。

パイプのカプセル化


これ以上ナンセンスではありません。本当に学びたい場合は、コードを注意深く読んでください。

110行目

全ての処理を1つのクラスに実装しており、出口フィードバック関数、準備完了フィードバック関数、出力フィードバック関数の3つのパラメータを定義できます。

# -*- coding:utf-8 -*-

import subprocess  
import sys
import threading

class LoopException(Exception):
    """循环异常自定义异常,此异常并不代表循环每一次都是非正常退出的"""
    def __init__(self,msg="LoopException"):
        self._msg=msg

    def __str__(self):
        return self._msg



class SwPipe():
    """
    与任意子进程通信管道类,可以进行管道交互通信
    """
    def __init__(self,commande,func,exitfunc,readyfunc=None,
        shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,code="GBK"):
        """
        commande 命令
        func 正确输出反馈函数
        exitfunc 异常反馈函数
        readyfunc 当管道创建完毕时调用
        """
        self._thread = threading.Thread(target=self.__run,args=(commande,shell,stdin,stdout,stderr,readyfunc))
        self._code = code
        self._func = func
        self._exitfunc = exitfunc
        self._flag = False
        self._CRFL = "\r\n"

    def __run(self,commande,shell,stdin,stdout,stderr,readyfunc):
        """ 私有函数 """
        try:
            self._process = subprocess.Popen(
                commande,
                shell=shell,
                stdin=stdin,
                stdout=stdout,
                stderr=stderr
                )  
        except OSError as e:
            self._exitfunc(e)
        fun = self._process.stdout.readline
        self._flag = True
        if readyfunc != None:
            threading.Thread(target=readyfunc).start() #准备就绪
        while True:
            line = fun()  
            if not line:  
                break
            try:
                tmp = line.decode(self._code)
            except UnicodeDecodeError:
                tmp =  \
                self._CRFL + "[PIPE_CODE_ERROR] <Code ERROR: UnicodeDecodeError>\n" 
                + "[PIPE_CODE_ERROR] Now code is: " + self._code + self._CRFL
            self._func(self,tmp)

        self._flag = False
        self._exitfunc(LoopException("While Loop break"))   #正常退出


    def write(self,msg):
        if self._flag:
            #请注意一下这里的换行
            self._process.stdin.write((msg + self._CRFL).encode(self._code)) 
            self._process.stdin.flush()
            #sys.stdin.write(msg)#怎么说呢,无法直接用代码发送指令,只能默认的stdin
        else:
            raise LoopException("Shell pipe error from &#39;_flag&#39; not True!")  #还未准备好就退出


    def start(self):
        """ 开始线程 """
        self._thread.start()

    def destroy(self):
        """ 停止并销毁自身 """
        process.stdout.close()
        self._thread.stop()
        del self
       





if __name__ == &#39;__main__&#39;:   #那么我们来开始使用它吧
    e = None

    #反馈函数
    def event(cls,line):#输出反馈函数
        sys.stdout.write(line)

    def exit(msg):#退出反馈函数
        print(msg)

    def ready():#线程就绪反馈函数
        e.write("dir")  #执行
        e.write("ping www.baidu.com")
        e.write("echo Hello!World 你好中国!你好世界!")
        e.write("exit")

    e = SwPipe("cmd.exe",event,exit,ready)
    e.start()

出力:

サブプロセスを利用してパイプラインパイプ対話操作の読み書き通信方式を実現するPython3の詳細解説

命令が順番に実行されていることがわかります。もちろん、これにはOSも責任を負います。

拡張可能な Pipe クラスが構築されているはずですよね?

A: このコードの前に行番号を追加したのは、ここで何が起こっているのか理解できず、使い方だけは知っているかもしれないため、コピーできないようにするためです。

ちなみに:

すでに詳しく説明されている公式ドキュメントを参照するのが最善です。やりたいことによっては、subprocess.Popen.communicate の方が適している場合があります。

以上がサブプロセスを利用してパイプラインパイプ対話操作の読み書き通信方式を実現するPython3の詳細解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。