博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
并发编程 线程
阅读量:5095 次
发布时间:2019-06-13

本文共 6179 字,大约阅读时间需要 20 分钟。

1.线程的概念:

  1. 什么是线程: 进程和线程都是虚拟单位,都是用来帮助我木门形象的描述某种事物

    进程 : 资源单位    线程:执行单位

    每一个进程都自带一个线程,线程才是真正的执行单位,进程只是在线程运行过程中提供代码运行所需要的资源

 

  2. 为什么要有线程:

    开进程 1 申请内存空间 耗资源,  拷贝代码, 耗资源   

    开线程  一个进程内可以起多个线程,并且线程与线程之间的数据是共享的

    开启线程的开销要远远小于开启进程的开销

2.Threading.Thread 创建线程模块

Thread实例对象的方法  # isAlive(): 返回线程是否活动的。  # getName(): 返回线程名。  # setName(): 设置线程名。threading模块提供的一些方法:  # threading.currentThread(): 返回当前的线程变量。  # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。  # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

 

3.代码的实现

  1.创建线程的两种方式

from threading import Threadimport timedef func(name):    print(f'{name}线程正在创建')    time.sleep(2)    print(f'{name}线程结束')# 开线程不需要在__main__代码块内 但是习惯性的还是写在__main__代码块内if __name__ == '__main__':    t = Thread(target=func,args=('小明',))    t.start()    print('主')
from threading import Threadimport timeclass MyThread(Thread):    def __init__(self,name):        super().__init__()        self.name = name    def run(self):        print(f'{self.name}线程正在创建')        time.sleep(2)        print(f'{self.name}线程结束')if __name__ == '__main__':    t = MyThread('小明')    t.start()    print('主')

  2.线程对象及其他方法:

from threading import Thread,current_thread,active_countimport timeimport osdef task(name,i):    print('%s is running'%name)    # print('子current_thread:',current_thread().name)    # print('子',os.getpid())    time.sleep(i)    print('%s is over'%name)# 开线程不需要在__main__代码块内 但是习惯性的还是写在__main__代码块内t = Thread(target=task,args=('egon',1))t1 = Thread(target=task,args=('jason',2))t.start()  # 告诉操作系统开辟一个线程  线程的开销远远小于进程t1.start()  # 告诉操作系统开辟一个线t1.join()  # 主线程等待子线程运行完毕print('当前正在活跃的线程数',active_count())# 小的代码执行完 线程就已经开启了print('主')# print('主current_thread:',current_thread().name)  # 线程名字# print('主',os.getpid())

   3. 守护线程:与进程方法相同,但需要注意的是:主线程的结束也就以为着进程的结束,主线程必须等待其他非守护线程的结束才能结束,也就是意味着子线程在运行的时候需要使用进程中的资源,而主线程一旦结束了资源也就销毁了

from threading import Thread,current_threadimport timedef task(i):    print(current_thread().name)    time.sleep(i)    print('GG')t = Thread(target=task,args=(1,))t.daemon = Truet.start()print('主')   '''Thread-1主     因为t线程为守护进程,主线程运行结束t线程也跟着结束'''

  4.  同一进程中线程之间的数据是共享的

from threading import Threadmoney = 666def task():    global money    money = 999t = Thread(target=task)t.start()t.join()print(money)   # 999 同一进程中线程间的数据是共享的

  5.  线程中的互斥锁与进程中的使用方法一致

from threading import Thread,Lockimport timen = 100def task(mutex):    global  n    mutex.acquire()    tmp = n    time.sleep(0.1)    n = tmp - 1    mutex.release()t_list = []mutex = Lock()for i in range(100):    t = Thread(target=task,args=(mutex,))  # 创建100个线程    t.start()      t_list.append(t)  # 将线程对象添加到列表中for t in t_list:  # 遍历线程对象列表    t.join()   # 等待所有线程程运行结束再执行主线程print(n)   # 0

  6. 用线程实现sockte服务端的并发:

    服务端:

import socketfrom threading import Threaddef talk(conn):    while 1:        try:            ret = conn.recv(1024)            if len(ret) == 0: break            print(ret)            conn.send(ret.upper())        except ConnectionResetError:            break    conn.close()sk = socket.socket()sk.bind(('127.0.0.1',8080))sk.listen()while 1:    conn,addr = sk.accept()    t = Thread(target=talk,args=(conn,))    t.start()

    客户端:

import socketsk = socket.socket()sk.connect(('127.0.0.1',8080))while 1:    sk.send(b'hello')    ret = sk.recv(1024)    print(ret)

  7: GIL全局解释器锁:

  

"""In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiplenative threads from executing Python bytecodes at once. This lock is necessary mainlybecause CPython’s memory management is not thread-safe."""

ps:python解释器有很多种 最常见的就是Cpython解释器

  GIL本质也是一把互斥锁:将并发变成串行牺牲效率保证数据的安全 他是用来阻止同一个进程下的多个线程的同时执行(同一个进程内多个线程无法实现并行但是可以实现并发)GIL的存在是因为CPython解释器的内存管理不是线程安全的,也就是说同一个进程中的多个线程再同一时间只有一个线程被cpu执行,GIL全局解释器锁只是针对线程的,进入IO自动释放

  总结.在执行多个计算密集型的任务时.在计算机单核的情况下开线程最好,在多核情况下开进程会效率更高

    .在执行多个IO密集型的任务时.开线程时最好的

  8:死锁与递归锁:当一个进程或线程中同时出现多把锁容易造成死锁显现,程序卡死

   递归锁: Rlock,可以多次acquire与release  当一个线程或进程中所有acquire都被release,其他的线程才能获得资源,注意使用递归锁时是链式赋值

    科学家吃面示例:

import timefrom threading import Thread,RLocklock1 = lock2 = RLock()def eat1(name):    lock2.acquire()    print('%s 抢到了面条'%name)    lock1.acquire()    print('%s 抢到了叉子'%name)    print('%s 吃面'%name)    lock1.release()    lock2.release()def eat2(name):    lock1.acquire()    print('%s 抢到了叉子' % name)    time.sleep(1)    lock2.acquire()    print('%s 抢到了面条' % name)    print('%s 吃面' % name)    lock2.release()    lock1.release()for name in ['小明','小黄','小亮']:    t1 = Thread(target=eat1,args=(name,))    t2 = Thread(target=eat2,args=(name,))    t1.start()    t2.start()

 

  

  9 信号量: Semaphore: 用锁的原理实现的,内置了一个计数器,在同一时间只能有指定数量的进程或线程执行某一段代码,如果把互斥锁比作一个车位的话,那么信号量相当于多个车位

  

from threading import Thread,Semaphore  # 线程使用信号量导入方法# from multiprocessing import Process,Semaphore  # 进程使用信号量导入方法import timeimport randomsm = Semaphore(5)  # 5个车位def func(name):    sm.acquire()  # 占车位    print(f'{name}占了一个车位')    time.sleep(random.randint(1,2))    sm.release()  # 让出车位    print(f'{name}让了一个车位')for i in range(20):    t = Thread(target=func,args=(i,))    t.start()'''同时占用车位最多不会超过5个,一个让出去另一个才会占用'''

  10:事件:event类似于join 不过事件是在处理两个子进程或子线程之间互相等待的过程

    常用方法:

from multiprocessing import Evente = Event()e.wait()  # 阻塞态,状态为True不堵塞,为False 堵塞e.is_set()  # 查看状态 e.set()  # False  ---> Truee.clear()  # True ---> False

    红绿灯示例:

from threading import Event,Threadimport timee = Event()def light():    print('红灯亮了')    time.sleep(3)    e.set()    print('绿灯亮了')def car(name):    print(f'{name}正在等红灯')    e.wait()    print(f'{name}可以行驶了')l = Thread(target=light)l.start()for i in range(10):    c = Thread(target=car,args=(i,))    c.start()

  11. 线程队列: 

    1: queue  队列 

import queueq = queue.Queue()q.put(1)q.put(2)print(q.get())  # 1print(q.get())  # 2

    2: Lifoqueue 堆栈

import queueq = queue.LifoQueue()  # 堆栈q.put(1)q.put(2)print(q.get())  # 2print(q.get())  # 1

    3: PriorityQueue  优先级队列

import queueq = queue.PriorityQueue() # 堆栈q.put((1,'a'))  # 放一个元组,第一个元素是优先级为int型,数字越小优先级越高q.put((0,'b'))  q.put((-1,'c'))q.put((1,'d'))  # 同一优先级,按照内容对应的ASCII码表来确认优先级print(q.get())  # (-1, 'c')print(q.get()) # (0, 'b')print(q.get()) # (1, 'a')print(q.get())  # (1, 'd')

 

转载于:https://www.cnblogs.com/yanglingyao/p/11342136.html

你可能感兴趣的文章
IOS push消息的数字不减少的问题
查看>>
mysql报错Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage
查看>>
MySQL的并行复制多线程复制MTS(Multi-Threaded Slaves)
查看>>
Django中间件
查看>>
Hdfs数据备份
查看>>
xcode 5.1安装vvdocument
查看>>
log4j:WARN No appenders could be found for logger
查看>>
Google翻译
查看>>
盖得化工--采集所有公司详细信息
查看>>
Logistic Ordinal Regression
查看>>
常用软件
查看>>
影响数据库访问速度的九大因素
查看>>
好玩的-记最近玩的几个经典ipad ios游戏
查看>>
MySQL更改默认的数据文档存储目录
查看>>
给出一个十六进制的数0xFF 0x80 (只有2“位”) 将其转换成有符号的一字节的十进制整数...
查看>>
替代微软IIS强大的HTTP网站服务器工具
查看>>
5、easyUI-菜单与按钮
查看>>
6.5 案例21:将本地数据库中数据提交到服务器端
查看>>
PyQt5--EventSender
查看>>
深入浅出Symfony2 - 结合MongoDB开发LBS应用
查看>>