美文网首页
Python ☞ day 15

Python ☞ day 15

作者: 浪子彦卿L | 来源:发表于2018-06-07 11:43 被阅读0次

Python学习笔记之 进程和线程

多任务的原理
  • 现代操作系统(Windows、Mac OS X、Linux、UNIX等)都支持“多任务”

    什么叫多任务???
    操作系统同时可以运行多个任务

    单核CPU实现多任务原理:操作系统轮流让各个任务交替执行,QQ执行2us,切换到微信,在执行2us,再切换到陌陌,执行2us……。表面是看,每个任务反复执行下去,但是CPU调度执行速度太快了,导致我们感觉就行所有任务都在同时执行一样

    多核CPU实现多任务原理:真正的秉性执行多任务只能在多核CPU上实现,但是由于任务数量远远多于CPU的核心数量,所以,操作西永也会自动把很多任务轮流调度到每个核心上执行
    并发:看上去一起执行,任务书多于CPU核心数
    并行:真正一起执行,任务数小于等于CPU核心数

    实现多任务的方式:
    1、多进程模式
    2、多线程模式
    3、协程模式
    4、多进程+多线程模式

进程VS线程
一、进程

对于操作系统而言,一个任务就是一个进程
进程是系统中程序执行和资源分配的基本单位。每个进程都有自己的数据段、代码段、和堆栈段

单任务现象
from time import sleep

def run():
    while True:
        print("sunck is a nice man")
        sleep(1.2)

if __name__ == "__main__":
    while True:
        print("sunck is a good man")
        sleep(1)

    # 不会执行到run方法,只有上面的while循环结束才可以执行
    run()
启动进程实现多任务
'''
multiprocessing 库
跨平台版本的多进程模块,提供了一个Process类来代表一个进程对象
'''

from multiprocessing import Process
from time import sleep
import os

#子进程需要执行的代码
def run(str):
    while True:
        # os.getpid()获取当前进程id号
        # os.getppid()获取当前进程的父进程id号
        print("sunck is a %s man--%s--%s"%(str, os.getpid(),os.getppid()))
        sleep(1.2)

if __name__ == "__main__":
    print("主(父)进程启动-%s"%(os.getpid()))
    #创建子进程
    #target说明进程执行的任务
    p = Process(target=run, args=("nice",))
    #启动进程
    p.start()

    while True:
        print("sunck is a good man")
        sleep(1)
父子进程的先后顺序
from multiprocessing import Process
from time import sleep
import os

def run(str):
    print("子进程启动")
    sleep(3)
    print("子进程结束")

if __name__ == "__main__":
    print("父进程启动")

    p = Process(target=run, args=("nice",))
    p.start()

    #父进程的结束不能影响子进程,让父进程等待子进程结束再执行父进程
    p.join()
    print("父进程结束")
全局变量在多个进程中不能共享
from multiprocessing import Process
from time import sleep

num = 100

def run():
    print("子进程开始")
    global num # num = 100
    num += 1
    print(num)
    print("子进程结束")

if __name__ == "__main__":
    print("父进程开始")

    p = Process(target=run)
    p.start()
    p.join()

    # 在子进程中欧修改全局变量对父进程中的全局变量没有影响
    # 在创建子进程时对全局变量做了一个备份,父进程中的与子进程中的num是完全不同的两个变量
    print("父进程结束--%d"%num)
启动大量子进程
from multiprocessing import Pool
import os, time, random

def run(name):
    print("子进程%d启动--%s" % (name, os.getpid()))
    start = time.time()
    time.sleep(random.choice([1,2,3]))
    end = time.time()
    print("子进程%d结束--%s--耗时%.2f" % (name, os.getpid(), end-start))


if __name__ == "__main__":
    print("父进程启动")

    #创建多个进程
    #进程池
    #表示可以同时执行的进程数量
    #Pool默认大小是CPU核心数
    pp = Pool(2)
    for i in range(3):
        #创建进程,放入进程池同意管理
        pp.apply_async(run,args=(i,))

    #在调用join之前必须先调用close,调用close之后就不能再继续添加新的进程了
    pp.close()
    #进程池对象调用join,会等待进程池中所有的子进程结束完毕再去执行父进程
    pp.join()

    print("父进程结束")
拷贝文件
import os, time
from multiprocessing import Pool



#实现文件的拷贝
def copyFile(rPath, wPath):
    fr = open(rPath, "rb")
    fw = open(wPath, "wb")
    context = fr.read()
    fw.write(context)
    fr.close()
    fw.close()


path = r"C:\Users\xlg\Desktop\Python-1704\day20\2、进程\file"
toPath = r"C:\Users\xlg\Desktop\Python-1704\day20\2、进程\toFile"


#读取path下的都有的文件
filesList = os.listdir(path)

#启动for循环处理每一个文件     
start = time.time()
for fileName in filesList:
    copyFile(os.path.join(path,fileName), os.path.join(toPath,fileName))
end = time.time()
print("总耗时:%0.2f" % (end-start))
多进程实现文件拷贝
import os, time
from multiprocessing import Pool



#实现文件的拷贝
def copyFile(rPath, wPath):
    fr = open(rPath, "rb")
    fw = open(wPath, "wb")
    context = fr.read()
    fw.write(context)
    fr.close()
    fw.close()


path = r"C:\Users\xlg\Desktop\Python-1704\day20\2、进程\file"
toPath = r"C:\Users\xlg\Desktop\Python-1704\day20\2、进程\toFile"






if __name__ == "__main__":
    # 读取path下的都有的文件
    filesList = os.listdir(path)

    start = time.time()
    pp = Pool(4)
    for fileName in filesList:
        pp.apply_async(copyFile, args=(os.path.join(path,fileName), os.path.join(toPath,fileName)))

    pp.close()
    pp.join()
    end = time.time()
    print("总耗时:%0.2f" % (end-start))
封装进程对象
    ''' 创建一个类文件'''

from multiprocessing import Process
import os, time

class SunckProcess(Process):
    def __init__(self,name):
        Process.__init__(self)
        self.name = name

    def run(self):
        print("子进程(%s-%s)启动" % (self.name, os.getpid()))
        #子进程的功能
        time.sleep(3)
        print("子进程(%s-%s)结束" % (self.name, os.getpid()))

from sunckProcess import SunckProcess

if __name__ == "__main__":
    print("父进程启动")

    #创建子进程
    p = SunckProcess("test")
    # 自动调用p进程对象的run方法
    p.start()
    p.join()

    print("父进程结束")
进程间通信
from multiprocessing import Process, Queue
import os, time

def write(q):
    print("启动写子进程%s" % (os.getpid()))
    for chr in ["A", "B", "C", "D"]:
        q.put(chr)
        time.sleep(1)
    print("结束写子进程%s" % (os.getpid()))

def read(q):
    print("启动读子进程%s" % (os.getpid()))
    while True:
        value = q.get(True)
        print("value = " + value)
    print("结束读子进程%s" % (os.getpid()))


if __name__ == "__main__":
    #父进程创建队列,并传递给子进程
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))

    pw.start()
    pr.start()

    #
    pw.join()
    #pr进程里是个死循环,无法等待其结束,只能强行结束
    pr.terminate()

    print("父进程结束")
二、线程
  • 在一个进程的内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”叫做线程

    线程通常叫做轻型的进程。线程是共享内存空间的并发执行的多任务,每一个线程都共享一个进程的资源

    线程是最小的执行单元,而进程由至少一个线程组成。如何调度进程和线程,完全由操作系统绝对,程序自己不能决定什么时候执行,执行多长时间

    模块
    1、_thread模块 低级模块
    2、threading模块 高级模块,对_thread进行了封装

启动一个线程
import threading,time


def run(num):
    print("子线程(%s)开始" % (threading.current_thread().name))

    #实现线程的功能
    time.sleep(2)
    print("打印", num)
    time.sleep(2)

    print("子线程(%s)结束" % (threading.current_thread().name))

if __name__ == "__main__":
    #任何进程默认就会启动一个线程,称为主线程,主线程可以启动新的子线程
    #current_thread():返回返回当前线程的实例
    print("主线程(%s)启动" % (threading.current_thread().name))

    #创建子线程                     线程的名称
    t = threading.Thread(target=run, name="runThread", args=(1,))
    t.start()

    #等待线程结束
    t.join()

    print("主线程(%s)结束" % (threading.current_thread().name))
线程间共享数据
import threading
'''
多线程和多进程最大的不同在于,多进程中,同一个变量,各自有一份拷贝存在每个进程中,互不影响。而多线程中,所有变量都由所有线程共享。所以,任何一个变量都可以被任意一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时修改一个变量,容易把内容改乱了。
'''

num = 0

def run(n):
    global num
    for i in range(10000000):
        num = num + n    #  15 = 9 + 6
        num = num - n    #  9

if __name__ == "__main__":
    t1 = threading.Thread(target=run, args=(6,))
    t2 = threading.Thread(target=run, args=(9,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    print("num =",num)


'''
线程1   num = num + 6
        num - 6  = 3

线程2   num = num + 9
        3 - 9  =  -6


'''
线程锁解决数据混乱
'''

两个线程同时工作,一个存钱,一个取钱

可能导致数据异常


思路:加锁,

'''

import threading

#锁对象
lock = threading.Lock()

num = 0
def run(n):
    global num

    for i in range(10000000):
        # 锁
        # 确保了这段代码只能由一个线程从头到尾的完整执行
        # 阻止了多线程的并发执行,包含锁的某段代码实际上只能以单线程模式执行,所以效率大大滴降低了
        # 由于可以存在多个锁,不同线程持有不同的锁,并试图获取其他的锁,可能造成死锁,导致多个线程挂起。只能靠操作系统强制终止
        '''
        lock.acquire()
        try:
            num = num + n    #  15 = 9 + 6
            num = num - n    #  9
        finally:
            #修改完一定要释放锁
            lock.release()
        '''

        #与上面代码功能相同,with lock可以自动上锁与解锁
        with lock:
            num = num + n
            num = num - n

if __name__ == "__main__":
    t1 = threading.Thread(target=run, args=(6,))
    t2 = threading.Thread(target=run, args=(9,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print("num =",num)
ThreadLocal.py
import threading

num = 0
#创建一个全局的ThreadLocal对象
#每个线程有独立的存储空间
#每个线程对ThreadLocal对象都可以读写,但是互不影响
local = threading.local()

def run(x, n):
    x = x + n
    x = x - n

def func(n):
    #每个线程都有local.x,就是线程的局部变量
    local.x = num
    for i in range(1000000):
        run(local.x, n)
    print("%s-%d"%(threading.current_thread().name, local.x))

if __name__ == "__main__":
    t1 = threading.Thread(target=func, args=(6,))
    t2 = threading.Thread(target=func, args=(9,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    print("num =",num)


#作用:为每个线程绑定一个数据库链接,HTTP请求,用户身份信息等,这样一个线程的所有调用到的处理函数都可以非常方便地访问这些资源
信号量控制线程数量
import threading

num = 0
#创建一个全局的ThreadLocal对象
#每个线程有独立的存储空间
#每个线程对ThreadLocal对象都可以读写,但是互不影响
local = threading.local()

def run(x, n):
    x = x + n
    x = x - n

def func(n):
    #每个线程都有local.x,就是线程的局部变量
    local.x = num
    for i in range(1000000):
        run(local.x, n)
    print("%s-%d"%(threading.current_thread().name, local.x))

if __name__ == "__main__":
    t1 = threading.Thread(target=func, args=(6,))
    t2 = threading.Thread(target=func, args=(9,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    print("num =",num)


#作用:为每个线程绑定一个数据库链接,HTTP请求,用户身份信息等,这样一个线程的所有调用到的处理函数都可以非常方便地访问这些资源
凑够一定数量才能一起执行
import threading, time

bar = threading.Barrier(3)

def run():
    print("%s--start"%(threading.current_thread().name))
    time.sleep(1)
    bar.wait()
    print("%s--end" % (threading.current_thread().name))


if __name__ == "__main__":
    for i in range(5):
        threading.Thread(target=run).start()
定时线程
import threading

def run():
    print("sunck is a good man")

#延时执行线程
t = threading.Timer(5, run)
t.start()

t.join()
print("父线程结束")
线程通信
import threading, time

def func():
    #事件对象
    event = threading.Event()
    def run():
        for i in range(5):
            #阻塞,等待事件的触发
            event.wait()
            #重置
            event.clear()
            print("sunck is a good man!!%d"%i)
    t = threading.Thread(target=run).start()
    return event

e = func()

#触发事件
for i in range(5):
    time.sleep(2)
    e.set()
生产者与消费者
import threading,queue,time,random

#生产者
def product(id, q):
    while True:
        num = random.randint(0, 10000)
        q.put(num)
        print("生产者%d生产了%d数据放入了队列" % (id, num))
        time.sleep(3)
    #任务完成
    q.task_done()


#消费者
def customer(id, q):
    while True:
        item = q.get()
        if item is None:
            break
        print("消费者%d消费了%d数据" % (id, item))
        time.sleep(2)
    # 任务完成
    q.task_done()



if __name__ == "__main__":
    # 消息队列
    q = queue.Queue()

    # 启动生产者
    for i in range(4):
        threading.Thread(target=product, args=(i,q)).start()

    # 启动消费者
    for i in range(3):
        threading.Thread(target=customer, args=(i,q)).start()
线程调度
import threading,time

#线程条件变量
cond = threading.Condition()

def run1():
    with cond:
        for i in range(0, 10, 2):
            print(threading.current_thread().name, i)
            #time.sleep(1)
            cond.wait()
            cond.notify()


def run2():
    with cond:
        for i in range(1, 10, 2):
            print(threading.current_thread().name, i)
            #time.sleep(1)
            cond.notify()
            cond.wait()


threading.Thread(target=run1).start()
threading.Thread(target=run2).start()
QQ练习
  • server端

      import tkinter
      import socket
      import threading
    
      win = tkinter.Tk()
      win.title("QQ服务器")
      win.geometry("400x400+200+20")
    
      users = {}
    
      def run(ck, ca):
          print("***********")
          userName = ck.recv(1024)
          users[userName.decode("utf-8")] = ck
          print(users)
    
          while True:
              rData = ck.recv(1024)
              dataStr = rData.decode("utf-8")
              #xym:sunck is a goodman
              infolist = dataStr.split(":")
              users[infolist[0]].send((userName.decode("utf-8") + "说+"+infolist[1]).encode("utf-8"))
    
    
    
    
    
      def start():
          ipStr = eip.get()
          portStr = eport.get()
          server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
          server.bind((ipStr, int(portStr)))
          server.listen(10)
          printStr = "服务器启动成功"
          text.insert(tkinter.INSERT, printStr)
          while True:
              ck, ca = server.accept()
              t = threading.Thread(target=run, args=(ck,ca))
              t.start()
    
    
      def startServer():
          s = threading.Thread(target=start)
          s.start()
    
    
      lableIp = tkinter.Label(win,text="ip").grid(row=0,column=0)
      lablePort = tkinter.Label(win,text="port").grid(row=1,column=0)
      eip = tkinter.Variable()
      eport = tkinter.Variable()
      entryIp = tkinter.Entry(win, textvariable=eip).grid(row=0,column=1)
      entryPort = tkinter.Entry(win, textvariable=eport).grid(row=1,column=1)
      button = tkinter.Button(win, text="启动", command=startServer).grid(row=2,column=0)
      text = tkinter.Text(win, width=30, height=10)
      text.grid(row=3,column=0)
    
    
      win.mainloop()
    
  • client端
    1、client1.py

      import tkinter
      import socket
      import threading
    
      win = tkinter.Tk()
      win.title("sunck")
      win.geometry("400x400+200+20")
    
      ck = None
    
      def getInfo():
          while True:
              data = ck.recv(1024)
              text.insert(tkinter.INSERT, data.decode("utf-8"))
    
      def connectServer():
          global ck
          ipStr = eip.get()
          portStr = eport.get()
          userStr = euser.get()
          client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
          client.connect((ipStr, int(portStr)))
          client.send(userStr.encode("utf-8"))
          ck = client
          #等待接收数据
          t = threading.Thread(target=getInfo)
          t.start()
    
      def sendMail():
          frient = efriend.get()
          sendStr = esend.get()
          sendStr = frient + ":" + sendStr
    
          ck.send(sendStr.encode("utf-8"))
    
      lableUser = tkinter.Label(win,text="userName").grid(row=0,column=0)
      euser = tkinter.Variable()
      entryUser = tkinter.Entry(win, textvariable=euser).grid(row=0,column=1)
    
      lableIp = tkinter.Label(win,text="ip").grid(row=1,column=0)
      eip = tkinter.Variable()
      entryIp = tkinter.Entry(win, textvariable=eip).grid(row=1,column=1)
    
      lablePort = tkinter.Label(win,text="port").grid(row=2,column=0)
      eport = tkinter.Variable()
      entryPort = tkinter.Entry(win, textvariable=eport).grid(row=2,column=1)
    
      button = tkinter.Button(win, text="连接", command=connectServer).grid(row=3,column=0)
    
      text = tkinter.Text(win, width=30, height=5)
      text.grid(row=4,column=0)
    
    
      esend = tkinter.Variable()
      entrySend = tkinter.Entry(win, textvariable=esend).grid(row=5,column=0)
    
    
    
      efriend= tkinter.Variable()
      entryFriend = tkinter.Entry(win, textvariable=efriend).grid(row=6,column=0)
      button2 = tkinter.Button(win, text="发送", command=sendMail).grid(row=6,column=1)
    
    
      win.mainloop()
    

    2、client2.py

      import tkinter
      import socket
      import threading
    
      win = tkinter.Tk()
      win.title("sunck")
      win.geometry("400x400+200+20")
    
      ck = None
    
      def getInfo():
          while True:
              data = ck.recv(1024)
              text.insert(tkinter.INSERT, data.decode("utf-8"))
    
      def connectServer():
          global ck
          ipStr = eip.get()
          portStr = eport.get()
          userStr = euser.get()
          client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
          client.connect((ipStr, int(portStr)))
          client.send(userStr.encode("utf-8"))
          ck = client
          #等待接收数据
          t = threading.Thread(target=getInfo)
          t.start()
    
      def sendMail():
          frient = efriend.get()
          sendStr = esend.get()
          sendStr = frient + ":" + sendStr
    
          ck.send(sendStr.encode("utf-8"))
    
      lableUser = tkinter.Label(win,text="userName").grid(row=0,column=0)
      euser = tkinter.Variable()
      entryUser = tkinter.Entry(win, textvariable=euser).grid(row=0,column=1)
    
      lableIp = tkinter.Label(win,text="ip").grid(row=1,column=0)
      eip = tkinter.Variable()
      entryIp = tkinter.Entry(win, textvariable=eip).grid(row=1,column=1)
    
      lablePort = tkinter.Label(win,text="port").grid(row=2,column=0)
      eport = tkinter.Variable()
      entryPort = tkinter.Entry(win, textvariable=eport).grid(row=2,column=1)
    
      button = tkinter.Button(win, text="连接", command=connectServer).grid(row=3,column=0)
    
      text = tkinter.Text(win, width=30, height=5)
      text.grid(row=4,column=0)
    
    
      esend = tkinter.Variable()
      entrySend = tkinter.Entry(win, textvariable=esend).grid(row=5,column=0)
    
    
    
      efriend= tkinter.Variable()
      entryFriend = tkinter.Entry(win, textvariable=efriend).grid(row=6,column=0)
      button2 = tkinter.Button(win, text="发送", command=sendMail).grid(row=6,column=1)
    
    
      win.mainloop()
    

    3、client3.py

      import tkinter
      import socket
      import threading
    
      win = tkinter.Tk()
      win.title("sunck")
      win.geometry("400x400+200+20")
    
      ck = None
    
      def getInfo():
          while True:
              data = ck.recv(1024)
              text.insert(tkinter.INSERT, data.decode("utf-8"))
    
      def connectServer():
          global ck
          ipStr = eip.get()
          portStr = eport.get()
          userStr = euser.get()
          client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
          client.connect((ipStr, int(portStr)))
          client.send(userStr.encode("utf-8"))
          ck = client
          #等待接收数据
          t = threading.Thread(target=getInfo)
          t.start()
    
      def sendMail():
          frient = efriend.get()
          sendStr = esend.get()
          sendStr = frient + ":" + sendStr
    
          ck.send(sendStr.encode("utf-8"))
    
      lableUser = tkinter.Label(win,text="userName").grid(row=0,column=0)
      euser = tkinter.Variable()
      entryUser = tkinter.Entry(win, textvariable=euser).grid(row=0,column=1)
    
      lableIp = tkinter.Label(win,text="ip").grid(row=1,column=0)
      eip = tkinter.Variable()
      entryIp = tkinter.Entry(win, textvariable=eip).grid(row=1,column=1)
    
      lablePort = tkinter.Label(win,text="port").grid(row=2,column=0)
      eport = tkinter.Variable()
      entryPort = tkinter.Entry(win, textvariable=eport).grid(row=2,column=1)
    
      button = tkinter.Button(win, text="连接", command=connectServer).grid(row=3,column=0)
    
      text = tkinter.Text(win, width=30, height=5)
      text.grid(row=4,column=0)
    
    
      esend = tkinter.Variable()
      entrySend = tkinter.Entry(win, textvariable=esend).grid(row=5,column=0)
    
    
    
      efriend= tkinter.Variable()
      entryFriend = tkinter.Entry(win, textvariable=efriend).grid(row=6,column=0)
      button2 = tkinter.Button(win, text="发送", command=sendMail).grid(row=6,column=1)
    
    
      win.mainloop()
    

相关文章

网友评论

      本文标题:Python ☞ day 15

      本文链接:https://www.haomeiwen.com/subject/hjawsftx.html