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()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Python多线程可以使用内置的`threading`模块来实现。这个模块提供了一些对象和方法,可以方便地创建和管理线程。 以下是一个简单的多线程示例,它创建了两个线程,每个线程都打印数字1到5: ```python import threading def print_numbers(): for i in range(1, 6): print(threading.current_thread().name, i) # 创建两个线程 t1 = threading.Thread(target=print_numbers) t2 = threading.Thread(target=print_numbers) # 启动线程 t1.start() t2.start() # 等待线程结束 t1.join() t2.join() print("All threads have finished.") ``` 在这个示例中,我们首先定义了一个`print_numbers()`函数,它用于打印数字1到5,并且在每个数字前面打印线程的名称。然后,我们创建了两个线程`t1`和`t2`,它们都指向`print_numbers()`函数。接下来,我们启动这两个线程,并等待它们完成,最后输出"All threads have finished."。 注意,`threading.current_thread().name`用于获取当前线程的名称。在这个示例中,我们没有指定线程的名称,因此它们将默认为"Thread-1"和"Thread-2"。 多线程可以提高程序的执行效率,但是也需要注意线程安全问题,比如并发访问共享变量可能会导致数据不一致的问题。因此,在编写多线程程序时,需要特别注意线程安全问题。 ### 回答2: Python多线程是指在一个程序中同时执行多个线程,每个线程都可以独立执行不同的任务。Python多线程是基于线程模块实现的,通过创建多个线程对象来实现多线程的功能。 Python多线程的使用需要导入threading模块,使用threading.Thread类来创建线程对象。通过调用线程对象的start()方法,线程就会开始执行。线程可以是执行同一个函数,也可以是执行不同的函数,甚至可以是执行不同的类的方法。 线程之间可以共享全局变量,但需要避免多个线程同时修改全局变量的情况,可以通过互斥锁机制来保证数据的一致性。 Python多线程的优点是能够提高程序的执行效率,特别是在IO操作较多的情况下,多线程可以充分利用CPU的空闲时间。另外,多线程还可以实现一些并发的功能,例如同时下载多个文件、同时处理多个网络请求等。 然而,Python多线程在处理CPU密集型任务上并不适用,因为在Python中,多线程并不能利用多核CPU的优势,由于Python的GIL(全局解释器锁)机制,多线程在CPU密集型任务上的效率并不比单线程高。 总结来说,Python多线程适用于IO密集型任务,能够提高程序的执行效率和实现并发的功能,但对于CPU密集型任务,单线程可能更适合。 ### 回答3: Python 多线程是指在一个程序中同时运行多个线程,每个线程独立执行其任务。Python 中的多线程可以通过使用 threading 模块来实现。 在 Python 中,多线程的主要优势是能够提升程序的执行效率。通过多线程,可以将耗时较长的任务分配给不同的线程来并行执行,从而缩短程序的总执行时间。这尤其适用于那些需要频繁进行网络请求、IO 操作或者计算密集型任务的程序。 使用 Python 的 threading 模块可以很方便地创建和管理线程。通过创建 Thread 对象并传入要执行的函数,就可以创建一个新的线程。可以使用 start() 方法来启动线程,并使用 join() 方法来等待线程执行完成。 需要注意的是,Python 中的多线程并不能真正实现并行执行,而是通过在不同任务之间快速切换来模拟并行。这是由于 Python 的全局解释器锁(GIL)的存在,它使得同一时间只有一个线程能够执行 Python 的字节码。因此,在计算密集型任务上,使用多线程并不能获得真正的并行加速。 另外,多线程在处理共享资源时需要注意线程安全问题。多个线程同时访问和修改共享数据可能会导致数据不一致或者竞争条件。在这种情况下,可以通过使用锁(Lock)等同步机制来确保数据的正确访问和更新。 总而言之,Python 多线程可以提升程序的执行效率,适用于需要进行网络请求、IO 操作或者并发处理的任务。然而,在计算密集型任务上,并不能实现真正的并行加速。同时,在处理共享资源时需要注意线程安全问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值