网站收藏链接怎么做台州关键词优化服务
今日内容概要
- 开启线程的两种方式
- TCP服务端实现并发效果
- 线程对象的join方法
- 线程间数据共享
- 线程对象属性及其他方法
- 守护线程
- 线程互斥锁
- GIL全局解释器锁
- 多进程与多线程的实际应用场景
今日内容详细
开启线程的两种方式
# import time
# from multiprocessing import Process
# from threading import Thread
#
#
# def task(name):
# print('%s is running' % name)
# time.sleep(1)
# print('%s is over' % name)
#
#
# # 开启线程不需要在main下面执行代码 直接书写可以
# # 但是我们还是习惯性的将启动命令写在下面
# t = Thread(target=task, args=('egon',))
# t.start() # 创建线程的开销非常小,几乎是代码一执行线程就已经创建了
# print('主')from threading import Thread
import timeclass MyThread(Thread):def __init__(self,name):# 重写了别人的方法 又不知道别人的方法里有啥,你就调用父类的方法super().__init__()self.name = namedef run(self):print("%s is running" % self.name)time.sleep(1)print('egon dsb')if __name__ == '__main__':t = MyThread('egon')t.start()print('主')
TCP服务端实现平发的效果
import socket
from threading import Thread
from multiprocessing import Process"""
服务端1.要有固定的IP和PORT2.24小时不间断提供服务3.能够支持并发
"""
server = socket.socket() # 括号内不加参数默认就是TCP
server.bind(('127.0.0.1', 8080))
server.listen(5)# 将服务的代码单独封装成一个函数
def task(conn):# 通信循环while True:try:data = conn.recv(1024)# 针对mac linux 客户端链接后if len(data) == 0: breakprint(data.decode('utf-8'))conn.send(data.upper())except ConnectionError as e:print(e)breakconn.close()# 链接循环
while True:conn, addr = server.accept() # 接客# 叫其他人来服务客户t = Thread(target=task,args=(conn,))# t = Process(target=task,args=(conn,))t.start()"""客服端"""
import socketclient = socket.socket()
client.connect(('127.0.0.1', 8080))while True:client.send('hello word'.encode('utf-8'))data = client.recv(1024)print(data.decode('utf-8'))
线程对象的join方法
from threading import Thread
import timedef task(name):print('%s is running' % name)time.sleep(3)print('%s over' % name)if __name__ == '__main__':t = Thread(target=task,args=('egon', ))t.start()t.join() # 主线程等待子线程结束print('主')
同一个进程下的多个线程数据是共享的
from threading import Thread
import timemoney = 100def task():global moneymoney = 666print(money)if __name__ == '__main__':t = Thread(target=task)t.start()t.join()print(money) # 666
线程对象属性及其他方法
from threading import Thread, active_count, current_thread
import os, timedef task(n):# print('hello world', os.getpid())print('hello world', current_thread().name)time.sleep(n)if __name__ == '__main__':t = Thread(target=task, args=(1,))t1 = Thread(target=task, args=(2,))t.start()t1.start()t1.join()print('主',active_count()) # 统计当前正在活跃的线程数# print('主',current_thread().name)# print('主',os.getpid())
守护线程
# from threading import Thread
# import time
#
#
# def task(name):
# print('%s is running' % name)
# time.sleep(1)
# print('%s over' % name)
#
#
# if __name__ == '__main__':
# t = Thread(target=task, args=('egon',))
# t.daemon = True
# t.start()
# print('主')"""
主线程结束后不会立刻结束 需要等待其他子线程结束才会结束因为主线程结束意味着所在的进程的结束
"""from threading import Thread
import timedef foo():print(123)time.sleep(1)print('end123')def func():print(456)time.sleep(3)print('end456')if __name__ == '__main__':t1 = Thread(target=foo)t2 = Thread(target=func)t1.daemon = Truet1.start()t2.start()print('主')
线程的互斥锁
from threading import Thread, Lock
import timemoney = 100
mutex = Lock()def task():global moneymutex.acquire()tmp = moneytime.sleep(0.1)money = tmp - 1mutex.release()if __name__ == '__main__':t_list = []for i in range(100):t = Thread(target=task)t.start()t_list.append(t)for t in t_list:t.join()print(money)
GIL全局解释器锁
"""
cpython
Jpython
pypypython
但是普遍使用的都是cpython因为cpython中的内存管理不是线程安全的
内存管理(垃圾回收机制)1.应用计数2.标记清楚3.分代回收"""
"""
重点:1.GIL不是python的特点而是cpython解释器的特点2.GIL是保证解释器级别的数据安全3.GIL会导致同一个进程下的多个线程的无法同时执行4.针对不同的数据还是需要加不同的锁处理5.解释性语言的通病:同一个进程下多线程无法执行
"""
GIL与普通互斥锁的区别
from threading import Thread, Lock
import timemoney = 100
mutex = Lock()def task():global moneymutex.acquire()tmp = moneytime.sleep(0.1)money = tmp - 1mutex.release()if __name__ == '__main__':t_list = []for i in range(100):t = Thread(target=task)t.start()t_list.append(t)for t in t_list:t.join()print(money)"""
100个线程起起来之后, 要先去抢GIL
我进入IO GIL自动释放 但我手上还有一个自己的互斥锁
其他线程虽然抢到了但是抢不到互斥锁
最终GIL还是回到自己的手上 自己去操作数据
"""
同一个进程下的多线程无法利用多核优势,是不是就没有了
"""
多线程是否有用要看具体情况
单核:四个任务(IO密集型\计算密集型)
多核:四个任务(IO密集型\计算密集型)
"""
# 计算密集型 每个任务都需要10s
单核(不用考虑)多进程:额外消耗资源多线程:节省开销
多核多进程:总耗时 10+多线程:总耗时 40+
# IO密集型 每个任务都需要10s
多核多进程:相对浪费资源多线程:更加节省资源
代码验证
# 计算机密集型# from threading import Thread
# from multiprocessing import Process
# import time
# import os
#
#
# def work():
# res = 1
# for i in range(1, 100000):
# res *= i
#
#
# if __name__ == '__main__':
# l = []
# print(os.cpu_count())
# start_time = time.time()
# for i in range(4):
# # p = Process(target=work) # 4.017219066619873
# # p.start()
# # l.append(p)
# t = Thread(target=work) # 13.573662042617798
# t.start()
# l.append(t)
# for p in l:
# p.join()
# print(time.time() - start_time)# IO密集型
from threading import Thread
from multiprocessing import Process
import time
import osdef work():time.sleep(2)if __name__ == '__main__':l = []print(os.cpu_count())start_time = time.time()for i in range(200):# p = Process(target=work) # 16.503886699676514# p.start()# l.append(p)t = Thread(target=work) # 2.04239821434021t.start()l.append(t)for p in l:p.join()print(time.time() - start_time)
总结
"""
多进程和多线程都有各自的优势,并且后面写项目的时候通常都是多进程下面再开多线程
这样既可以利用多核要可以节省资源消耗
"""
内容回顾
-
开启线程的两种方式
""" 开进程和开启线程的步骤基本都是一样的 只是导入的模块不一样而已 开进程必须写在main下面而开线程无需这么做类的对象调用方法 类的继承重写run方法 """
-
TCP服务端实现并发
"""将接客与服务的活分开"""
-
线程对象join方法
"""等待当前线程对象结束之后 再继续往下执行"""
-
同一个进程内的多个数据是共享的
""" 同一个进程可以开启多个线程 进程:资源单位 线程:执行单位 """
-
线程对象属性和方法
""" current_thread.name active_count 统计当前正在活跃的线程 """
-
守护线程
""" 主线程必须等待所有非守护线程的结束后才能结束 t.daemon = True t.start() """
-
线程互斥锁
""" 当多个线程在操作同一份数据的时候会造成数据错乱 这个时候为了保证数据安全 通常加锁处理 锁:将并发变成串行,降低了程序的运行效率但保证了数据安全 """
-
GIL全局解释器锁
""" 1.GIL是cpython解释器的特点不是python的特点!!! 2.GIL本质也是一把互斥锁 解释器级别的锁 3.它的存在是因为cpython解释器内存管理不是线程安全的 垃圾回收机制引用技术标记清除分代回收 4.也就意味着GIL的存在导致了一个进程下的多个线程无法利用多核优势 5.针对不同的数据应该加不同的锁来处理 """