python线程和进程操作(含例子学习)

    技术2022-07-10  239

    线程

    线程是CPU使用的基本单元,由主线程来创建,并使用这个进程的资源。python中thread模块提供支持,通过以下两种方法创建线程:

    通过threading.Thread直接在线程中运行函数通过继承threading.Thread类来创建线程

    用threading.Thread直接在线程中运行函数

    这里我们就用这个函数创建一个线程,简单模拟打印平方,这个函数原型我们首先熟悉一下,尤其是各个参数

    Thread(group=None, target=None, Name=None, args=(), kwargs={}, *, daemon = None) # 其中target参数就是运行的函数,args是传入函数的参数元组。

    例子:并行打印平方

    运行效果:(并行效果哟!)

    import threading def thrfun(x, y): for i in range(x, y): print(str(i * i) + ';') ta = threading.Thread(target=thrfun, args=(1, 6)) tb = threading.Thread(target=thrfun, args=(16, 21)) tc = threading.Thread(target=thrfun, args=(11,15)) ta.start() tb.start() tc.start()

    博主用pycharm是同步执行,但是代码本身含义是并行。因此大家如果使用pycharm同步的话,可以用ipython试试。

    通过继承threading.Thread类来创建线程

    这个创建类来继承就行了,了解面向对象的同学应该明白,肯定有init的方法,我们把要执行的函数写到run函数里,因为它继承可以重载。我们还是仍以求平方为例子

    例子:继承类并行打印平方

    实验效果: 实验代码:

    import threading class myThread(threading.Thread): def __init__(self,mynum): super().__init__() self.mynum = mynum def run(self): for i in range(self.mynum,self.mynum+5): print(str(i*i)+';') ma = myThread(1) mb = myThread(16) ma.start() mb.start()

    线程类Thread使用

    上面的例子我们只是用thread里的init和run方法,还有几个重要的方法和属性一起熟悉一下: 方法:

    join([timeout])isAlive()

    属性:

    namedaemon # join()方法的作用是当某个线程或函数执行时需等另一个线程 # --完成后才能继续,则应调用另一个线程的join()方法 # 其中可选参数timeout用于指定线程运行的最长时间 # isAlive()方法用于查看线程是否运行 # 属性 # name属性是线程设置的线程名 # daemon属性用来设置线程是否随主线程退出而退出,一般来说,其属性值为True不会随主线程退出而退出

    下面就以两个例子演示join和daemon的使用

    例子:同步执行平方

    实验效果: 实验代码:

    import threading import time def thrfun(x, y, thr=None): if thr: thr.join() else: time.sleep(2) for i in range(x, y): print(str(i * i) + ';') ta = threading.Thread(target=thrfun, args=(1, 6)) tb = threading.Thread(target=thrfun, args=(16, 21,ta)) ta.start() tb.start()

    这里的join函数本传入了ta,也就是tb线程应等待ta结束后运行。

    例子:将函数转到后台执行不做输出

    实验效果: 实验代码:

    import threading import time class myThread(threading.Thread): def __init__(self,mynum): super().__init__() self.mynum = mynum def run(self): time.sleep(1) for i in range(self.mynum, self.mynum + 5): print(str(i * i) + ';') def main(): print('start...') ma = myThread(1) mb = myThread(16) ma.daemon =True mb.daemon = True ma.start() mb.start() print('end...') if __name__ == '__main__': main()

    将打印平方的工作,都交到后台去了,这里不做执行

    RLock与Event讲解

    线程的隔离性就不需要彼此修改,因此产生锁的概念。python中threading模块中的对象Lock和RLock进行简单的同步,对于同一个时刻只允许一个线程操作的数据对象,可以进行加锁和解锁进行隔离。过程原型如下

    lock = threading.RLock() # 创建lock对象 lock.acquire() # 开始锁定 pass # pass就是指我们要执行的语句和操作 lock.release() # 释放锁

    线程间的通信我们用Event对象,Event实例管理着一个内部标志,通过set()方法会将它设置为True,使用clear()方法会将它重置为False,wait([timeout])方法会使当前线程阻塞标志为True. 下面我们用两个例子进行简单模拟,一个是打印数据每次加30,第二个是两个进程通信

    例子:RLock对线程数据加30后输出

    实验效果: 实验代码:

    import threading import time class myThread(threading.Thread): def run(self): global x lock.acquire() for i in range(3): x += 10 time.sleep(1) print(x) lock.release() x = 0 lock = threading.RLock() def main(): thrs = [] for item in range(5): thrs.append(myThread()) for item in thrs: item.start() if __name__ == '__main__': main()

    例子:模拟两个线程通过Event进行通信

    实验效果 实验代码:

    import threading import time class myThreada(threading.Thread): def run(self): evt.wait() print(self.name,':Good morning!') evt.clear() time.sleep(1) evt.set() time.sleep(1) evt.wait() print(self.name,":I'm fine,thank you.") class myThreadb(threading.Thread): def run(self): print(self.name,':Good morning!') evt.set() time.sleep(1) evt.wait() print(self.name,":How are you?") evt.clear() time.sleep(1) evt.set() evt = threading.Event() def main(): John = myThreada() John.name = 'John' Smith = myThreadb() Smith.name = 'Smith' John.start() Smith.start() if __name__ == '__main__': main()

    进程

    使用python的多进程模块可以将工作分配给不受锁定限制的单独子进程。python3对多进程支持的是multiprocessing模块和subprocess模块。使用multiprocessing模块创建和使用多线程,基本上和threading模块的使用方法一致。创建进程使用multiprocessing.Process对象来完成。

    进程基础

    下面我们用subprocess创建模块,它用来创建新进程,获取进程的输入、输出以及错误信息。它提供了更高级的接口,可以替换os.system、os.spawn*、popen等,subprocess模块的基本函数如下:

    call(args,*,stdin = None,stdout=None,stderr = None,shell=False,timeout=None) # 创建新进程运行程序,输入输出绑定到父进程,返回新进程的退出码 check_call(args,*,stdin = None,stdout=None,stderr = None,shell=False,timeout=None) # 创建新进程运行程序,输入和输出绑定到父进程,退出码为0正常返回 # 否则,返回CalledProcessError getstatusoutput(cmd) # 创建新进程运行程序,元组形式返回新进程退出码和输出 getoutput(cmd) # 创建新进程运行程序,返回新进程输出(字符串) call(args,*,input=None,stdin = None,stdout=None,stderr = None,shell=False, universal_newlines=False,timeout=None) # 创建新进程运行程序,返回新进程的输出(bytesarray) stdin,stdout,stderr 用来处理输入、输出、错误信息shell 是否使用一个中间shell来执行(可以使用shell相关变量等)input 为命令行提供一个输入信息(字符串),不能与stdin同时用universal_newline 返回值和输入值为字符串而不是bytes

    下面我们用一个例子演示如何操作,

    例子:用进程打开py文件,并输出

    实验准备,新建protest.py,内容为:

    print('hello world!')

    实验效果: 实验代码:

    import subprocess print('call() test:',subprocess.call(['python','protest.py'])) print('') print('check_call() test:',subprocess.check_call(['python','protest.py'])) print('getstatusoutput() test:',subprocess.getstatusoutput(['python','protest.py'])) print('') print('getoutput() test:',subprocess.getoutput(['python','protest.py'])) print('') print('check_output() test:', subprocess.check_output(['python','protest.py']))

    用Popen类创建进程

    Popen也可以创建新进程,它是一个类,因此初始化参数如下:

    class Popen(args, bufsize = -1,executable = None, stdin = None, stdout = None,stderr = None, preexec_fn = None,close_fds = True,shell = False,cwd = None,env = None, universal_newlines = False,startupinfo = None, creationflags = 0, restore_signals = True,start_new_session = False,pass_fds =())

    因为大部分参数都跟上面类似,我们用到啥就直接等于啥。以下常用方法

    poll() 检查子进程是否结束wait(timeout=None) 等待子进程结束communicate(input=None,timeout=None) 用于和紫禁城交互,发送标准输入数据,返回由标准输出和错误输出构成的元组

    其中常用属性有:

    pid 子进程的pidreturncode 子进程的退出码

    下面用两个例子演示popen创建子进程和communicate函数的效果

    例子:popen产生子进程,执行py源代码

    实验准备:创建protest.py文件,内容为:

    print('hello world!') print(a)

    实验效果:因a没有赋值,所以会报错 实验代码:

    import subprocess prcs = subprocess.Popen(['python','protest.py'],stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) prcs.communicate('These strings are from stdin.') print('subprocess pid:',prcs.pid) print('\nSTDOUT:') print(str(prcs.communicate()[0])) print('STDERR:') print(prcs.communicate()[1])

    例子:communicate实现进程数据传递

    实验准备,创建protest1.py内容为:

    a = input() a = a.split(' ') a[0] = str(int(a[0])+1) print(' '.join(a))

    实验效果 实验代码:

    import subprocess processes = [] psum = 5 for i in range(psum): processes.append(subprocess.Popen(['python','protest1.py'],stdout=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True, shell = True)) processes[0].communicate('0 bouquet of flowers!') for before,after in zip(processes[:psum],processes[1:]): after.communicate(before.communicate()[0]) print('\nSum of Process :%d'%psum) print() for item in processes: print(item.communicate()[0])

    总结

    通过线程与进程的学习,能自己创建进程与线程,在后面的学习中,可以对这些不断强化,进而完成掌握的功底!程序员是码出来的,加油!

    Processed: 0.043, SQL: 9