python多线程

                                python多线程
定义:

并行:真的多任务
并发:假的多任务
不同进程之间靠队列来实现
程序运行起来,叫进程,进程是资源分配的单位,线程执行代码,一个线程只能执行一个任务,想要执行多个任务,就需要多线程
协程依赖于线程,线程依赖于进程,协程切换需要资源相当少,所以效率就会很高
重构:把现在代码推倒,重新写
进程是资源分配的单位
线程是操作系统调度的单位
进程切换需要的资源很大,效率很低
线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)
GIL即全局解释锁的缩写,保证了了同一时刻只有一个线程在一个CPU上执行字节码,
无法将多个线程映射到多个CPU上
协程切换任务资源很小,效率很高
多进程,多线程根据cpu核数不一样可能是并行的,但是协程是一个线程中,所以是并发的
每一个程序都有一个主线程,主线程然后分出来子线程,线程运行没有先后顺序,可以通过时间延迟
迭代器
for temp in obj:
pass
1.判断obj是否是可以迭代的(有__iter__函数是可以迭代的,有__iter__函数跟__next__函数是迭代器)
2.在第一步成立的前提下,调用iter函数,得到obj对象的__iter__方法的返回值,
3.__iter__方法的返回值是一个迭代器
函数名+():这个是调用函数
函数名:这个是告诉函数在哪里
当调用Thread的时候,不会创建线程
当调用Thread创建出来的实例对象的start方法地时候,才会创建线程以及让这个线程开始运行
类:封装,继承,多态
在一个函数中,对全局变量进行修改的时候,到底是否需要使用global进行说明,要看是否对全局
变量的执行指向进行了修改:
如果修改了执行,即让全局变量指向了一个新地方,那么必须使用global,如果,仅仅是修改了指向
的空间数据,此时不用必须使用global.
代码变成了进程:进程是资源分配的单位,线程实现了多任务(调度的单位),线程不能独立执行,必须依存在进程中
进程:把一台电视机的零件都给你
线程:把零件组装
多进程:(写时拷贝)
进程:能够完成多任务,比如,在一台电脑上能够运行
迭代器:迭代是取数据的过程.先判断集合中是否有数据,(使用极少的空间,返回生成的方式)
如果有,就取出一个数据,接着再判断集合中是否有数据, 如果有再接着取出一个数据,这样往复循环直到所有数据都取出来了.
为什么要有迭代器:单列集合分为有序 list 集合和无序set集合
List接口有索引,我们可以通过for循环+get方法来获取数据,但是Set接口这边没有索引,不能通过for循环+get方式获取数据.
所以Collection接口就搞了一种通用的方式方便所有的集合来获取数据,就是迭代器(Iterator)
多线程:

import threading #  线程模块
import time

def sing():
    print("唱歌")
def danche():
    print("跳舞")

def main():
    for i in range(5):
        t1 = threading.Thread(target=sing)
        t2 = threading.Thread(target=danche)
        t1.start()
        t2.start()

if __name__  =="__main__":
    main()

多线程传递参数问题

import threading #  线程模块
import time

def sing():
    print("唱歌")
def danche():
    print("跳舞")

def main():
    for i in range(5):
        t1 = threading.Thread(target=sing)
        t2 = threading.Thread(target=danche)
        t1.start()
        t2.start()

if __name__  =="__main__":
    main()

查看线程主线程

import time

def test1():
    for i in range(5):
        print("test1")
def test2():
    for i in range(5):
        print("test2")

def main():
    t1=threading.Thread(target=test1)
    t2 = threading.Thread(target=test2)#不仅可以写函数名,还可以
    t1.start()
    time.sleep(1)
    t2.start()
    time.sleep(1)
    print(threading.enumerate())


if __name__ == "__main__":
    main()

多线程掉用类

#使用情况满足条件
#一个线程里面做的事情比较复杂,我分成多个函数来做,一般创建一个类

import threading
import time

class MyThread(threading.Thread):
    def run(self):
        for i in range(3):
            time.sleep(1)
            msg="I'm"+self.name+'@'+str(i)# name属性中保存的是当前线程的名字
            print(msg)
        self.login()#为了达到多线程的目的,只用在run()函数里面调用
        self.register()
    def login(self):
        print("这是登陆。。。")
    def register(self):
        print("这个是注册。。。")

def main():
    t=MyThread()
    t.start()  # 只会运行类里面run()方法,没有运行不了,其他不运行
if __name__ == "__main__":
    main()

全局变量资源竞争问题

import time

# 定义一个全局变量

g_num=0  
def test1():
    global g_num
    for i in range(1000000):
        g_num +=1
        """1.获得g_num的值
           2.对g_num加1
           3.把所得结果赋值给g_num 
        """
def test2():
    global g_num
    for i in range(1000000):
        g_num+=1
def main():
    #target指定将来 这个线程去哪个函数执行代码
    #args指定将来调用 函数的时候 传递什么数据过去(元组)
    t1=threading.Thread(target=test1)
    t2=threading.Thread(target=test2)
    t1.start()
    t2.start()
    time.sleep(5)
    print("主线程%d"%g_num)
if __name__ == "__main__":
    main()

多线程解决资源竞争问题:

import threading
import time

# 定义一个全局变量

g_num=0
def test1():
    global g_num
    #上锁,如果之前没有上锁,那么此时上锁成功
    #如果上锁之前已经被上锁了,那么此时会堵塞这里,直到这个索恩被解开为止
    mutex.acquire()
    for i in range(1000000):
        g_num +=1
        #解锁
        """1.获得g_num的值
           2.对g_num加1
           3.把所得结果赋值给g_num 
        """
    mutex.release()
def test2():
    global g_num
    mutex.acquire()
    for i in range(1000000):
        g_num+=1
    mutex.release()
#创建一个互斥锁,默认是没有上锁的
mutex=threading.Lock()
def main():
    #target指定将来 这个线程去哪个函数执行代码
    #args指定将来调用 函数的时候 传递什么数据过去(元组)
    t1=threading.Thread(target=test1)
    t2=threading.Thread(target=test2)
    t1.start()
    t2.start()
    time.sleep(10)
    print("主线程%d"%g_num)
if __name__ == "__main__":
    main()

通过队列完成进程之间通信

import multiprocessing


def download_from_web(q):
    #模拟从网上下载的数据
    data=[11,22,33,44]
    #向队列中写入数据
    for temp in data:
        q.put(temp)
        print(temp)

def analysis_data(q):
    waitting_analysis_data=list()
    #从对列中获取数据  
    while True:
        data=q.get()
        waitting_analysis_data.append(data)

        if q.empty():
            break
    print(waitting_analysis_data)
def main():
    #1.创建一个队列
    q=multiprocessing.Queue()
    #2.创建多个进程,将队列的引用当作实参进行传递里面
    p1=multiprocessing.Process(target=download_from_web,args=(q,))
    p2 = multiprocessing.Process(target=analysis_data,args=(q,))
    p1.start()
    p2.start()
    pass
if __name__ == "__main__":
    main()

创建进程池:

import multiprocessing
import random
import time, os
def worker(msg):
    t_start=time.time()#  开始执行时间
    print("%s开始执行,进程号为%d"%(msg,os.getpid()))
    #random.random()随机生成0-1之间的浮点数
    time.sleep(random.random()*2)
    t_stop=time.time()#  执行结束时间
    print(msg,"执行完毕,耗时0.2f"%(t_stop-t_start))


def main():
    # po=multiprocessing.pool(3)# 定义一个进程池,最大数为3
    po = multiprocessing.Pool(3)
    for i in range(0, 10):
        # pool().apply_async(要调用的目标,(传递给目标的参数元组,))
        # 每次循环将会用空闲出来的子进程去调用目标
        po.apply_async(worker, (i,))
    print("---start---")
    po.close()  # 关闭进程池,关闭后po不在接受新的请求
    po.join()  # 等待po中的进程执行完,必须放到close语句之后,如果不使用进程池,主进程会等各个分支执行完再结束
    print("---end---")
if __name__ == "__main__":
    main()

yield完成多任务:

import time


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


def main():
    t1=task_1()
    t2=task_2()
    while True:
        next(t1)
        next(t2)
    pass
if __name__ == "__main__":
    main()

yield生成器

ef create_num(all_num):
    a, b = 0,1
    current_num = 0
    while current_num < all_num:
        # print(a)
        yield a #如果一个函数中有yield语句,那么这个就不再是函数,而是一个生成器的模板
        a, b = b,a+b
        current_num += 1


#如果再调用create_num的时候,发现这个函数中有yield,那么此时,不是调用函数,而是创建一个生成器对象
obj = create_num(10)
obj1=create_num(2)#  又创建了一个生成器对象(生成器对象之间是对立的)
res=next(obj)
print(res)

send 启动生成器

def create_num(all_num):
    a, b = 0,1
    current_num = 0
    while current_num < all_num:
        # print(a)

        ret= yield a #如果一个函数中有yield语句,那么这个就不再是函数,而是一个生成器的模板
        print(ret)
        a, b = b,a+b
        current_num += 1
obj = create_num(10)
ret=next(obj)
print(ret)
ret= obj.send("haha")#  (启动生成器)
# send里面的数据会 传递第七行ret结果,然后ret保存这个结果
# send的结果是下一次调用yield时,yield后面的值
print(ret)
# ret=next(obj)
# print(ret)
# ret= obj.send("haha")
# for num in obj:
#     print(num)

迭代器:

# 迭代器

from collections.abc import Iterable
# isinstance(a,b)验证第一个参数是不是第二个参数的类型
# print(isinstance([11,22],Iterable))

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

    def add(self,name):
        self.names.append(name)
    def __iter__(self):
        # 如果想要一个对象称为一个可以迭代的对象,既可以使用for,那么必须使用__iter__方法
        return classmate1(self)
class classmate1(object):
    def __init__(self,obj):
        self.obj=obj
        self.current_num=0
    def __iter__(self):
        pass
    def __next__(self):
        if self.current_num<len(self.obj.names):
            ret = self.obj.names[self.current_num]
            self.current_num+=1
            return ret
        else:
            raise StopIteration#  返回self,需要把下面的__next__弄到类里面,此类里面

classmate=Classmate()
classmate.add("老王")
classmate.add("老张")
classmate.add("老李")
for name in classmate:
    print(name)

通过异常判断生成器结束:

# 生成器是一类特殊的迭代器


def create_num(all_num):
    a, b = 0,1
    current_num = 0
    while current_num < all_num:
        # print(a)
        yield a #如果一个函数中有yield语句,那么这个就不再是函数,而是一个生成器的模板
        a, b = b,a+b
        current_num += 1
    return "ok"


#如果再调用create_num的时候,发现这个函数中有yield,那么此时,不是调用函数,而是创建一个生成器对象
obj = create_num(10)
obj1=create_num(2)#  又创建了一个生成器对象(生成器对象之间是对立的)
res=next(obj)
print(res)
# for num in obj:
#     print(num)

while True:
    try:
        ret=next(obj1)
        print(ret)
    except Exception as ret:
        print(ret.value)
        break

通过异常完成进程间通信

import multiprocessing


def download_from_web(q):
    #模拟从网上下载的数据
    data=[11,22,33,44]
    #向队列中写入数据
    for temp in data:
        q.put(temp)
        print(temp)

def analysis_data(q):
    waitting_analysis_data=list()
    #从对列中获取数据  
    while True:
        data=q.get()
        waitting_analysis_data.append(data)

        if q.empty():
            break
    print(waitting_analysis_data)
def main():
    #1.创建一个队列
    q=multiprocessing.Queue()
    #2.创建多个进程,将队列的引用当作实参进行传递里面
    p1=multiprocessing.Process(target=download_from_web,args=(q,))
    p2 = multiprocessing.Process(target=analysis_data,args=(q,))
    p1.start()
    p2.start()
    pass
if __name__ == "__main__":
    main()

迭代器_斐波那契数列

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

    def __next__(self):
        if self.current_num < self.all_num:
            ret = self.a
            self.a, self.b = self.b, self.a+self.b
            self.current_num+=1
            return ret
        else:
            raise StopIteration
    def __iter__(self):
        return self
fibo=Fibonacci(10)
for num in fibo:
    print(num)

gevent实现多任务:

# jevent遇到延时就切换,没有则不切换

import gevent
import time


#f1,f2,f3可以用一个f就行了,下面这样写是为了方便理解
def f(n):
    for i in range(n):
        print(gevent.getcurrent(),i)
        gevent.sleep(1)#必须使用gevent.sleep(),如果使用time.sleep()是不可以的,如果想用需要用gevent打补丁
# def f1(n):
#     for i in range(n):
#         print(gevent.getcurrent(),i)
#         gevent.sleep(1)
# def f2(n):
#     for i in range(n):
#         print(gevent.getcurrent(),i)
#         gevent.sleep(1)
# def f3(n):
#     for i in range(n):
#         print(gevent.getcurrent(),i)
#         gevent.sleep(1)
#
g1=gevent.spawn(f,5)
g2=gevent.spawn(f,5)
g3=gevent.spawn(f,5)
g1.join()#  耗时
g2.join()
g3.join()

gevent打补丁

# jevent遇到延时(等待)就切换,没有则不切换

import gevent
import time
from gevent import monkey

monkey.patch_all()#  将程序中用到的耗时操作的代码,换为gevent中自己实现的模块

#f1,f2,f3可以用一个f就行了,下面这样写是为了方便理解
def f(n):
    for i in range(n):
        print(gevent.getcurrent(),i)
        time.sleep(1)#必须使用gevent.sleep(),如果使用time.sleep()是不可以的,如果想用需要用gevent打补丁

# g1=gevent.spawn(f,5)
# g2=gevent.spawn(f,5)
# g3=gevent.spawn(f,5)
# g1.join()#  耗时
# g2.join()
# g3.join()
# 15-20代码等价于下面代码:
gevent.joinall([gevent.spawn(f,5),gevent.spawn(f,5),gevent.spawn(f,5)])

多任务聊天器:

import socket
import threading

def rec_msg(udp_socket):
    """接受数据"""
    while True:
        recv_data=udp_socket.recvfrom(1024)
        print(recv_data[0].decode("gbk"))
def send_msg(udp_socket,dest_ip,dest_port):
    """发送数据"""
    while True:
        send_data = input("请输入要发送的数据:")
        udp_socket.sendto(send_data.encode("gbk"), (dest_ip, dest_port))

def main():
    """完成udp聊天器的整体控制"""
    #1.创建套接字
    udp_socket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    #2.绑定本地信息
    udp_socket.bind(("",7890))
    #3.获取对方的Ip
    # dest_ip=input("请输入对方的ip")
    # dest_port=int(input("请输入对方的端口sort"))
    dest_ip ="192.168.124.56"
    dest_port=8080
    #创建两个线程,去执行相应的功能
    t_recv=threading.Thread(target=rec_msg,args=(udp_socket,))
    s_send=threading.Thread(target=send_msg,args=(udp_socket, dest_ip,dest_port))
    t_recv.start()
    s_send.start()


if __name__ == "__main__":
    main()

迭代图片下载器:

import urllib.request
import gevent
from gevent import monkey

monkey.patch_all()
def downloader(img_name,img_url):
    req=urllib.request.urlopen(img_url)
    img_content = req.read()
    with open(img_name,"wb") as f:
        f.write(img_content)
def main():
    g1=gevent.spawn(downloader,"1.1.jpg","https://rpic.douyucdn.cn/asrpic/191118/6259669_4652236_0f7d3_2_2207.jpg")
    g2=gevent.spawn(downloader,"2.2.jpg","https://rpic.douyucdn.cn/live-cover/roomCover/2019/11/15/ef6a286d4c6edb17b1ef6406fbc96e02_big.jpg")
    g1.join()#  耗时
    g2.join()
if __name__ == "__main__":
    main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值