python基础-Thread基本使用,查看线程数,锁,进程实现多任务,通过Queue队列进程间通信,进程池Pool,迭代器,生成器,gevent协程完成多任务,图片下载案例

简答来一个demo来演示一下

import threading
import time


def sing():
    for i in range(5):
        print("正在唱歌")
        time.sleep(1)


def dance():
    for i in range(5):
        print("正在跳舞")
        time.sleep(1)

def main():
    t1 = threading.Thread(target=sing) # sing是实例对象,而sing()是返回值
    t2 = threading.Thread(target=dance)
    t1.start()
    t2.start()
if __name__ == '__main__':
    main()

查看正在运行的线程

import threading
import time

def test1():
    for i in range(5):
        print("test01---->{}".format(i))
        time.sleep(1)

def test2():
    for i in range(5):
        print("test02---->{}".format(i))
        time.sleep(1)


def main():
    threading.Thread(target=test1).start()
    threading.Thread(target=test2).start()
    print(threading.enumerate())  # 查看当前线程个数
# [<_MainThread(MainThread, started 140312615470848)>, <Thread(Thread-1, started 140312584259328)>, <Thread(Thread-2, started 140312575866624)>]


if __name__ == '__main__':
    main()

args元祖参数

args指定将来调用函数的时候传递什么参数过去

import threading
import time

def test1(num):
   num.append(18)
   print(num)

def test2(num):
    num.append(55)
    print(num)


def main():
    threading.Thread(target=test1,args=([11,11],)).start()
    threading.Thread(target=test2,args=([10,19],)).start()
   

if __name__ == '__main__':
    main()

互斥锁

# 创建锁
mutex = threading.Lock()
# 锁定
mutex.acquire()
# 释放
mutex.release()

使用互斥锁解决资源竞争的问题
在有可能出现资源竞争的部分,全部用锁套起来

import threading
import time


def test1(num):
    # 上锁
    mutex.acquire()
    num.append(18)
    print(num)
    # 解锁
    mutex.release()

def test2(num):
    # 上锁
    mutex.acquire()
    num.append(55)
    print(num)
    # 解锁
    mutex.release()

def main():
    threading.Thread(target=test1,args=([11,11],)).start()
    threading.Thread(target=test2,args=([10,19],)).start()

# 创建一个互斥锁
mutex = threading.Lock()

if __name__ == '__main__':
    main()

实现多任务udp聊天器

import threading
import socket

def send_data(socket):
    while True:
        send_data = input("请输入您要发送的数据")
        socket.sendto(send_data.encode("utf8"), ("127.0.0.1", 7788))

def revc_data(socket):
    while True:
        revc_data = socket.recvfrom(1024)
        print(revc_data[0].decode("utf8"))

def main():
    # 创建stock
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    # 绑定port
    udp_socket.bind(("127.0.0.1",8899))

    # 发送数据

    # 接收数据


    threading.Thread(target=send_data, args=(udp_socket,)).start()

    threading.Thread(target=revc_data, args=(udp_socket,)).start()



if __name__ == '__main__':
    main()

使用进程实现多任务

进程的问题就是:浪费资源

import multiprocessing
import time

def test1():
    while True:
        print("1-----")
        time.sleep(1)

def test2():
    while True:
        print("2----")
        time.sleep(1)

def main():
    multiprocessing.Process(target=test1).start()
    multiprocessing.Process(target=test2).start()


if __name__ == '__main__':
    main()

通过Queue队列进程间通信

队列:先进先出
相关方法:

from multiprocessing import Queue
q = Queue # 初始化一个Queue对象,最多可以接收3条put信息
# put放入数据
q.put("xxxx")
# 判断是否满了 
q.full()
# 判断锁否空了
q.empyt()
#取数据用get
q.get()

数据下载分析demo演示

import multiprocessing

def download_to_web(q):
    # 网络下载数据
    data=[11,22,33,44]
    for i in data:
        q.put(i)
    print("下载完成等待提取")


def analysis_data(q):
    # 数据处理
    lst = []
    while True:
        print("提取。。。。。")
        data = q.get()
        lst.append(data)
        if q.empty():
            break
    # 模拟进行数据处理
    print("数据处理完成")


def main():
    # 创建一个队列
    q = multiprocessing.Queue()
    # 把队列当作实参进行参数传递
    multiprocessing.Process(target=download_to_web,args=(q,)).start()
    multiprocessing.Process(target=analysis_data,args=(q,)).start()


if __name__ == '__main__':
    main()

进程池Pool

使用场景:

面对大量任务,可以重复利用进程,减少了一个创建和销毁的所消耗的资源

相关方法:

import mutiprocessing import Pool

po = Pool(3)
po.apply_async(要调用的目标,传递给目标的元祖参数)

po.close() # 关闭进程池
po.join() # 阻塞主进程,等待进程池跑完在解堵,运行主进程、结束程序

当主进程与进程池进行通信必须使用:

q = multiprocessing.Manager.Queue()

实现多进程版的copy文件夹

import multiprocessing
import os

def copy_file(q,file_name,folder_name,new_name):
    f = open(folder_name+"/"+ file_name,"rb")
    content = f.read()
    f.close()

    f1 = open(new_name+"/"+file_name,"wb")
    f1.write(content)
    f1.close()

    # 拷贝完成往队列里放入一个信息
    q.put(file_name)




def main():
    # 获取用户要copy的文件夹名称
    folder_name = input("请输入您要copy文件夹的名称:")
    # 创建一个新的文件夹
    try:
        new_name = folder_name+"附件"
        os.mkdir(new_name)

    except:
        pass

    # 获取文件夹中所有的待copy的文件名字 os.listdir("路径")
    file_names=os.listdir(folder_name)


    # 复制原文件夹中的文件,到新文件夹中去
    po = multiprocessing.Pool(3)

    # 创建一个队列q
    q = multiprocessing.Manager().Queue()

    for file_name in file_names:
        po.apply_async(copy_file,args=(q,file_name,folder_name,new_name))


    po.close()
    #po.join()
    # 进程间通信
    all_file_name = len(file_names)
    copy_num = 0
    while True:
        file_name = q.get()
        print("已经完成copy:{}".format(file_name))
        copy_num +=1
        print("拷贝进度{}{}".format(copy_num*100/all_file_name,"%"))
        if copy_num >=all_file_name:
            print("拷贝完成亲!!!")
            break


if __name__ == '__main__':
    main()

迭代器

我们定义一个类Classmate

class Classmate(object):
    def __init__(self):
        self.names = []

    def add(self,name):
        self.names.append(name)

# 实例化一下
classmate = Classmate()

# 调用一下add
classmate.add("老外")
classmate.add("张三")
classmate.add("李四")

# 看一下能否迭代
for name in classmate:
    print(name) # TypeError: 'Classmate' object is not iterable

那么我们怎么能让一个类可以迭代那?

一个类有__iter__方法叫可迭代
当有__iter__和__next__方法后叫迭代器
每for一次就调用一次__next__返回什么for出来就是什么

class Classmate(object):
    def __init__(self):
        self.names = []

    def add(self,name):
        self.names.append(name)
        self.current_num = 0

    def __iter__(self):
        """
        如果想要一个对象称之为可迭代对象,即可以使用for,
        那么必须实现__iter__方法
        """
        return self

    def __next__(self):
        if self.current_num<len(self.names):
            ret = self.names[self.current_num]
            self.current_num+=1
            return ret
        else:
            raise StopIteration # 此异常是专门用于迭代器退出的


# 实例化一下
classmate = Classmate()

# 调用一下add
classmate.add("老外")
classmate.add("张三")
classmate.add("李四")

# 看一下能否迭代
for name in classmate:
    print(name)

迭代器的使用场景是什么?会迭代器和不会迭代器有什么区别?

当有一个很大的列表数据,当我们不会迭代器,就要把整个数据集展示出来,占用极大的内存
而迭代器,他不是数据集,而是一个可以产生数据集的方式,占用极小内存。

使用迭代器实现斐伯纳耶数列

class Fibonacci(object):
    def __init__(self,all_num):
        self.all_num = all_num
        self.current_num = 0
        self.a = 0
        self.b = 1

    def __iter__(self):
        return self

    def __next__(self):
        lst = []
        if self.current_num<self.all_num:
            for i in range(self.all_num):
                lst.append(self.a)
                self.a,self.b = self.b,self.a+self.b
                self.current_num+=1

            return lst
        else:
            raise StopIteration


fibo = Fibonacci(10)
for i in fibo:
    print(i)

生成器:是迭代器特殊版本

生成器创建方式一、小括号()

# []返回的是一个列表
nums = [x*2 for x in range(10)] # [0,2,4,6,8,12,14,18]

#()返回的是一个生成器,优点:占用空间小,他产生的不是数据集,而是生成数据集的方法
nums =(x*2 for x in range(10) # <generator object <genexpr> at 0x7f04e12d9690>

生成器创建方式二、函数末尾添加yield就是一个生成器

如果一个函数中yield语句,那么这个就不是函数,而是一个生成器模板

def create_num(all_num):
    a, b = 0,1
    current_num =0
    while current_num<all_num:
        yield a
        a, b = b, a+b
        current_num+=1
        
for i in create_num(10):
    print(i)

启动生成器

方法一:next(放入生成器)
第一种方法不能往生成器内传入参数
方法二:生成器.send()
第二种方法是可以实现往生成器内传入参数,此参数代替yield的值

生成器的主要用途:实现多任务

import time

def task_1():
    while True:
        print("---1---")
        time.sleep(0.1)
        yield

def task_2():
    while True:
        print("---2---")
        time.sleep(0.1)
        yield

def main():
    t1 = task_1()
    t2 = task_2()
    while True:
        next(t1)
        next(t2)

if __name__ == '__main__':
    main()

gevent协程完成多任务

安装gevent

pip3 insatll gevent
import gevent
import time
from gevent import monkey  #补丁会检查代码,把所有延时内容都会替换成gevent的延时

monkey.patch_all() # 打补丁

def test1(n):
    for i in range(n):
        print("---A---")
        time.sleep(0.5) # 碰到延时gevent会进行切换

def test2(n):
    for i in range(n):
        print("---B---")
        time.sleep(0.5) # 碰到延时gevent会进行切换
        
gevent.joinall([gevent.spawn(test1,5),
                gevent.spawn(test2,5)
                ])

协程是一个程序等待时,我们切换其他程序进行

使用协程实现图片下载案例

import urllib.request
import gevent
from gevent import monkey
import random
monkey.patch_all()


def downloader(img_url):
    req = urllib.request.urlopen(img_url)
    img_content = req.read()

    with open(str(random.randint(1,80))+"1.jpg", "wb")as f:
        f.write(img_content)

def main():
    gevent.joinall([gevent.spawn(downloader,"图片url"),
                    gevent.spawn(downloader,"图片url")])


if __name__ == '__main__':
    main()

协程、进程、线程对比

进程占用资源大,效率低
线程资源耗费小,效率一般
进程线程是属于并行
而,协程是利用了线程在执行任务时等待的期间去执行其他的任务,效率最高,属性并发

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值