Python基础学习(十五)--进程,线程

一、进程

(一)什么是进程

当我们双击时,操作系统将程序装载到内存中,操作系统为它分配资源,然后才能运行。运行起来的程序就称之为进程。

程序和进程的对应关系是:程序只有一个,但可执行多次;进程可以有多个。

进程是资源分配的最小单位。

(二)创建进程

1.单进程

import time
def sing():
    for i in range(3):
        print('我在唱第{}句歌词'.format(i+1))
        time.sleep(1)
def dance():
    for i in range(3):
        print('我在跳第{}段舞蹈'.format(i+1))
        time.sleep(1)
if __name__ == '__main__':
    sing()
    dance()

2.多进程

from multiprocessing import Process
import time
def sing():
    for i in range(3):
        print('我在唱第{}句歌词'.format(i+1))
        time.sleep(1)
def dance():
    for i in range(3):
        print('我在跳第{}段舞蹈'.format(i+1))
        time.sleep(1)
if __name__ == '__main__':
    t1=Process(target=sing)
    t2=Process(target=dance)
    t1.start()
    t2.start()

 多进程时,每个进程需要一份系统资源,资源不共享,两个进程互不干扰。

from multiprocessing import Process
count=0
def hs1():
    global count
    for i in range(1000):
        count+=1
    print('函数1:',count)
def hs2():
    global count
    for i in range(1000):
        count+=1
    print('函数2:',count)
if __name__ == '__main__':
    p1=Process(target=hs1)
    p2=Process(target=hs2)
    p1.start()
    p2.start()

父子进程的ID,传参: 

from multiprocessing import Process
import os
def sing(num):
    print('参数:',num,'进程的ID:',os.getpid(),'父进程ID:',os.getppid())

def dance(num):
    print('参数:',num,'进程的ID:',os.getpid(),'父进程ID:',os.getppid())

if __name__ == '__main__':
    print('主进程ID:',os.getpid())
    p1=Process(target=sing,args=(9,))
    p2=Process(target=dance,args=(99,))
    p1.start()
    p2.start()

(三)进程的状态

1.就绪状态

当进程已经分配到出CPU以外的所有必要的资源,只要获得处理机便可立即执行。

2.执行状态

当进程已获得处理机,其程序正在处理机上执行。

3.阻塞状态

正在执行的进程,由于等待某个时间发生而无法执行时,便放弃处理机而处于阻塞状态。

(四)队列--一种先进先出的线性数据结构

put()--向队列中存放数据,若已满,此方法将阻塞至有空间可用为止。

get()--返回队列中的一个项目,若列表为空,此方法将阻塞,直至队列中有项目可用为止。

qsize()--获取队列中的数据数量

full()--判断队列是否已满

empty()--判断队列是否已空

from multiprocessing import Queue
q=Queue(4)    # 4--队列容量,若超出,程序阻塞
q.put('包子')
q.put('香蕉')
q.put('西瓜')
print(q.full())

while q.qsize()>0:
    print(q.get())
print(q.empty())

block=False--不等待,直接抛出异常

from multiprocessing import Queue
q=Queue(3)
q.put(10)
q.put(20)
q.put(30)
try:
    q.put(40,block=False)    # 不等待,直接抛出异常
except:
    print('队列已满,无法再存放数据')
print('结束')
from multiprocessing import Queue
a=Queue(3)
a.put(10)
a.put(20)
a.get()
a.get()
try:
    a.get(block=False)
except:
    print('队列已空,取不出东西了')
print('结束')

(五)进程之间的通信(需要借助队列)

from multiprocessing import Queue,Process
import time

def producer(q):
    for i in range(10):
        bz='包子:%d'%(i+1)
        print('生产'+bz)
        q.put(bz)
        time.sleep(1)
def consumer(q):
    for i in range(10):
        bz=q.get()
        print('消费'+bz)
if __name__ == '__main__':
    q=Queue(3)
    p1=Process(target=producer,args=(q,))
    p2=Process(target=consumer,args=(q,))
    p1.start()
    p2.start()

(六)进程子类化

from multiprocessing import Queue,Process
import os,time
class SubProcess(Process):
    def __init__(self,x):
        super().__init__()
        self.x=x
    # 重新编写run函数,覆盖父类的run方法。进程启动时调用此方法
    def run(self):
        for i in range(self.x):
            print('启动进程',i,os.getpid())
            time.sleep(1)
if __name__ == '__main__':
    p=SubProcess(3)
    # 不同于直接调用run函数,这里是启动进程
    p.start()
    p1=SubProcess(3)
    p1.start()

(七)进程池

1.阻塞式--同一时刻只跑一个进程

from multiprocessing import Pool
import time
def hs(name):
    for i in range(5):
        print(name,i)
        time.sleep(1)
if __name__ == '__main__':
    p=Pool(3)
    a='abcde'
    for x in a:
        p.apply(hs,(x,))    # 阻塞式,同时只跑一个进程
    p.close()

2.非阻塞式--同一时刻可跑多个进程,最多要看进程池的容量

from multiprocessing import Pool
import time
def hs(name):
    for i in range(5):
        print(name,i)
        time.sleep(1)
if __name__ == '__main__':
    p=Pool(3)
    a='abcde'
    for x in a:
        # 非阻塞式,同时可跑多个进程,最多要看进程池的容量。
        # 必须加join(),在close()后加
        p.apply_async(hs,(x,))
    p.close()
    p.join()    # 阻塞主进程,等待子进程结束

非阻塞式应用

1.通信

from multiprocessing import Pool
import time
def zuoye(name):
    print(name+'在写代码')
    time.sleep(1)
    return name+'写完代码了'
def wan(status):
    print('出去玩,'+status)
if __name__ == '__main__':
    p=Pool(1)
    # callback--回调
    p.apply_async(zuoye,('张三',),callback=wan)
    p.close()
    p.join()

2.模拟下载器原理

from multiprocessing import Pool
import time
def downLoad(movie):
    for i in range(5):
        print(movie,'下载进度%.2f%%'%((i+1)/5*100))
        time.sleep(1)
    return movie
def alert(name):
    print(name,'下载完毕,请收看')
if __name__ == '__main__':
    movies=['哪吒','金刚葫芦娃','黑猫警长','小青龙','亚洲飞鹰','A计划']
    p=Pool(4)
    for movie in movies:
        p.apply_async(downLoad,args=(movie,),callback=alert)
    p.close()
    p.join()

二、线程

(一)概念

进程是资源拥有者,创建、撤销与切换存在较大的内存开销,因此需要引入轻型进程,即线程。

线程是CPU调度的最小单位(程序真正执行的时候调用的是线程)

(二)进程和线程之间的关系

每一个进程中至少有一个线程。

进程中的所有线程共享进程中的所有资源。

(三)使用threading模块创建线程

from threading import Thread
count=0
def hanshu1():
    global count
    for i in range(100):
        count+=1
    print('函数1',count)
def hanshu2():
    global count
    for i in range(100):
        count+=1
    print('函数2',count)
if __name__ == '__main__':
    t1=Thread(target=hanshu1)
    t2=Thread(target=hanshu2)
    t1.start()
    t2.start()
from threading import Thread
import time
import os
def sing():
    for i in range(10):
        print('唱歌%d'%(i+1))
        time.sleep(1)
    print(os.getpid())
def dance():
    for i in range(10):
        print('跳舞%d'%(i+1))
        time.sleep(1)
    print(os.getpid())
if __name__ == '__main__':
    t1=Thread(target=sing)
    t2=Thread(target=dance)
    t1.start()
    t2.start()

1.setDaemon()--将当前线程设置为守护线程来守护主线程

from threading import Thread
import time
def get(num):
    for i in range(num):
        print(i)
        time.sleep(1)
if __name__ == '__main__':
    t1=Thread(target=get,args=(5,))
    # 需要在子线程开启之前设置
    # 当主线程结束时,守护线程也就结束,不管是否执行完成
    t1.setDaemon(True)
    t1.start()
    print('主线程结束了')

2.join()方法--当前线程执行完后其他线程才会继续执行。 

3.threading模块提供的方法

threading.currentThread()--返回当前的线程变量。

threading.enumerate()--返回一个包含正在运行的线程的列表。

threading.active_count()或threading.activeCount()--返回正在运行的线程的个数。与len(threading.enumerate())有相同的结果。

from threading import Thread
import threading
import time
def sing():
    for i in range(10):
        print('唱歌%d'%(i+1),threading.current_thread())
        time.sleep(2)
def dance():
    for i in range(10):
        print('跳舞%d'%(i+1),threading.current_thread())
        time.sleep(1.5)
if __name__ == '__main__':
    t1=Thread(target=sing,name='刘德华')
    t2=Thread(target=dance,name='张惠妹')
    t1.start()
    t2.start()
    print(threading.enumerate())
    print(threading.activeCount())
    t1.join()
    t2.join()
    print('主线程结束')

(四)线程子类化

import time,os
from threading import Thread
class T(Thread):
    def __init__(self,name):
        super().__init__()
        self.name=name
    def run(self):
        for i in range(10):
            print(self.name,'跳舞%d'%(i+1))
            time.sleep(1)
        print(os.getpid())
class C(Thread):
    def __init__(self,name):
        super().__init__()
        self.name=name
    def run(self):
        for i in range(10):
            print(self.name, '唱歌%d' % (i + 1))
            time.sleep(1)
        print(os.getpid())
if __name__ == '__main__':
    t=T('张三')
    c=C('张三')
    t.start()
    c.start()

(五)共享全局变量

import threading
g_num=10
def hanshu1():
    global g_num
    g_num+=5
def hanshu2():
    print(g_num)
if __name__ == '__main__':
    t1=threading.Thread(target=hanshu1)
    t2=threading.Thread(target=hanshu2)
    t1.start()
    t2.start()

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值