首页 > 其他分享 >多线程、GIL全局解释器锁、协程

多线程、GIL全局解释器锁、协程

时间:2022-11-21 17:47:05浏览次数:45  
标签:多线程 协程 list start 线程 time print import GIL

目录

多进程实现TCP服务端并发

服务端:
import socket
from multiprocessing import Process

def get_server():
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    return server

def get_talk(sock):
    while True:
        data = sock.recv(1024)
        print(data.decode('utf8'))
        sock.send(data.upper())

if __name__ == '__main__':
    server = get_server()
    while True:
        sock, addr = server.accept()
        # 开设多进程去聊天
        p = Process(target=get_talk,args=(sock,))
        p.start()

客户端:
import socket
client = socket.socket()
client.connect(('127.0.0.1',8080))
while True:
    client.send(b'hello baby')
    data = client.recv(1024)
    print(data)

互斥锁代码实操

# 锁:建议只加载操作数据的部分 否则整个程序的效率会极低
from multiprocessing import Process,Lock
import time
import json
import random

def search(name):
    with open(r'data.json','r',encoding='utf8') as f:
        data = json.load(f)
    print('%s查看票 目前剩余:%s' %(name,data.get('ticket_num')))

def buy(name):
    # 先查询票数
    with open(r'data.json','r',encoding='utf8') as f:
        data = json.load(f)
    # 模拟网络延迟
    time.sleep(random.randint(1,3))
    # 买票
    if data.get('ticket_num') > 0:
        with open(r'data.json','w',encoding='utf8') as f:
            data['ticket_num'] -= 1
            json.dump(data,f)
        print('%s 买票成功' % name)
    else:
        print('%s 买票失败' % name)

def run(name,mutex):
    search(name)
    mutex.acquire()  # 抢锁
    buy(name)
    mutex.release()  # 释放锁

if __name__ == '__main__':
    mutex = Lock() # 产生一把锁
    for i in range(10):
        p = Process(target=run,args=('用户%s号' %i,mutex))
        p.start()

"""
锁有很多种 但是作用都一样
    行锁 表锁 ...
"""

线程理论

进程
	进程其实是资源单位 表示一块内存空间
线程
	线程才是执行单位 表示真正的代码指令

我们可以将进程比喻是车间 线程是车间里面的流水线
一个进程内部至少含有一个线程
1.一个进程内可以开设多个线程
2.同一个进程下的多个线程数据是共享的
3.创建进程与线程的区别
	创建进程的消耗要远远大于线程

创建线程的两种方式

from threading import Thread
from multiprocessing import Process
import time

def task(name):
    print(f'{name} is running')
    time.sleep(0.1)
    print(f'{name} is over')

if __name__ == '__main__':
    start_time = time.time()
    # p_list = []
    # for i in range(100):
    #     p = Process(target=task,args=('用户%s' %i,))
    #     p.start()
    #     p_list.append(p)
    # for p in p_list:
    #     p.join()
    # print(time.time() - start_time)
    # 多线程
    # t_list = []
    # for i in range(100):
    #     t = Thread(target=task,args=('用户%s'%i,))
    #     t.start()
    #     t_list.append(t)
    # for t in t_list:
    #     t.join()
    # print(time.time() - start_time)

# 方式一
# t = Thread(target=task,args=('jason',))
# t.start()
# print('主线程')
'''创建线程无需考虑反复执行的问题'''

#方式二
class MyThread(Thread):
    def run(self):
        print('run is running')
        time.sleep(1)
        print('run is over')

obj = MyThread()
obj.start()
print('主线程')

线程的诸多特性

1.join方法
2.同进程内多个线程数据共享
3.current_thread()
4.active_count()

from threading import Thread
import time

def task(name):
    print(f'{name} is running')
    time.sleep(1)
    print(f'{name} is over')

t = Thread(target=task, args=('jason',))
t.start()
t.join()
print('主线程')
'''
执行结果
jason is running
jason is over
主线程
'''

import time
from threading import Thread,current_thread,active_count
import os

money = 1000

def task():
    time.sleep(3)
    global  money
    print(current_thread().name)
    print('子线程进程号>>>>',os.getpid())

for i in range(10):
    t = Thread(target=task)
    t.start()
    print(money)

print('存活的线程数',active_count()) # 存活的线程数 11
print(current_thread().name)  # MainThread
print('主线程进程号>>>:',os.getpid()) # 主线程进程号>>>: 31484

GIL全局解释器锁

# 官方文档对GIL的解释
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.
"""
1.在CPython解释器中存在全局解释器锁简称GIL
	python解释器有很多类型
		CPython JPython PyPython (常用的是CPython解释器)
2.GIL本质也是一把互斥锁 用来阻止同一个进程内多个线程同时执行(重要)
3.GIL的存在是因为CPython解释器中针对多线程无法保证数据的安全。(内存管理不是线程安全的,垃圾回收机制)
	垃圾回收机制
		引用计数、标记清除、分代回收
"""

验证GIL的存在

from threading import Thread
num = 100

def task():
    global  num
    num -= 1
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(num)

GIL与普通互斥锁

既然CPython解释器中有GIL 那么我们以后写代码是不是就不需要操作锁了
"""
GIL只能确保同进程内多线程数据不会被垃圾回收机制弄乱
并不能确保程序里面的数据是否安全

# from threading import Thread
# num = 100
#
# def task():
#     global  num
#     num -= 1
# 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(num)  # 0
import time
from threading import Thread,Lock

num = 100

def task(mutex):
    global num
    mutex.acquire()
    count = num
    time.sleep(0.1)
    num = count - 1
    mutex.release()

mutex = Lock()
t_list = []
for i in range(100):
    t = Thread(target=task,args=(mutex,))
    t.start()
    t_list.append(t)
for t in t_list:
    t.join()
print(num)  # 0
""""

python多线程是否有用

需要分情况
	情况1
		单个cpu
		多个cpu
	情况2
		IO密集型(代码有IO操作)
		计算密集型(代码没有IO)
1.单个CPU
	IO密集型
		多进程
			申请额外的空间 消耗更多的资源
		多线程
			消耗资源相对较少 通过多道技术
		ps:多线程有优势!!!
	计算密集型
		多进程
			申请额外的空间 消耗更多的资源(总耗时+申请空间+拷贝代码+切换)
		多线程
			消耗资源相对较少 通过多道技术(总耗时+切换)
		ps:多线程有优势!!!
2.多个CPU
	IO密集型
		多进程
			总耗时(单个进程的耗时+IO+申请空间+拷贝代码)
		多线程
			总耗时(单个进程的耗时+IO)
		ps:多线程有优势!!!
	计算密集型
		多进程
			总耗时(单个进程的耗时)
		多线程
			总耗时(多个进程的综合)
		ps:多进程完胜!!!
		
from threading import Thread
from multiprocessing import Process
import os
import time

def work():
    # 计算密集型
    res = 1
    for i in range(1, 100000):
        res *= i

if __name__ == '__main__':
    # print(os.cpu_count())  # 16 查看当前计算机CPU个数
    start_time = time.time()
    p_list = []
    for i in range(16):  # 一次性创建16个进程
        p = Process(target=work)
        p.start()
        p_list.append(p)
    for p in p_list:  # 确保所有的进程全部运行完毕
        p.join()
    # t_list = []
    # for i in range(16):
    #     t = Thread(target=work)
    #     t.start()
    #     t_list.append(t)
    # for t in t_list:
    #     t.join()
    print('总耗时:%s' %(time.time()-start_time))  # 获取总的耗时

"""
计算密集型
    多进程:4.119809150695801
    多线程:38.7866096496582
"""

from threading import Thread
from multiprocessing import Process
import os
import time

def work():
    time.sleep(2)  # 模拟纯IO操作

if __name__ == '__main__':
    start_time = time.time()
    # t_list = []
    # for i in range(100):
    #     t = Thread(target=work)
    #     t.start()
    # for t in t_list:
    #     t.join()
    p_list = []
    for i in range(100):
        p = Process(target=work)
        p.start()
    for p in p_list:
        p.join()

    print('总耗时:%s' %(time.time() - start_time))

"""
IO密集型
    多线程:0.008002042770385742
    多进程:0.8913090229034424
"""

死锁现象

信号量

event事件

进程池与线程池

协程

协程实现并发

标签:多线程,协程,list,start,线程,time,print,import,GIL
From: https://www.cnblogs.com/winter-yu1989/p/16912104.html

相关文章

  • 一起聊聊 Kotlin 协程
    正文大家好,我是朱涛,最近刚刚通过Google的认证,成为了Android以及Kotlin领域的谷歌开发者专家(GoogleDeveloperExpert)。这周我在GDG(GoogleDeveloperGroup)和字......
  • 15.多线程并发在电商系统下的追本溯源(2)
                                                         ......
  • C++多线程
    c++多线程多线程其实非常简单多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序。一般情况下,两种类型的多任务处理:基于进程和基于线程......
  • Golang中协程调度器底层实现( G、M、P)
    三个必知的核心元素。(G、M、P)G:Goroutine的缩写,一个G代表了对一段需要被执行的Go语言代码的封装M:Machine的缩写,一个M代表了一个内核线程,等同于系统线程P:Processor的缩写......
  • python的协程
    python协程库gevent学习--gevent数据结构及实战(三)gevent学习系列第三章,前面两章分析了大量常用几个函数的源码以及实现原理。这一章重点偏向实战了,按照官方给出的ge......
  • 【Java】JDK5.0新增的创建多线程的方式:实现Callable接口,使用线程池
    1.实现Callable接口方式和实现Runnable接口相比call()可以有返回值。call()可以抛出异常,被外面的操作捕获,获取异常信息。Callable是支持泛型的。实现Callable接口......
  • kotlin的协程
    一、关于协程库的导入1、使用下载包的方式可以到该网站下载https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core对应的协程库本地调试......
  • 为仿真器添加eCos多线程调试支持,GDBServer Extender 0.0.1 使用说明
    可以使用RedBoot或者仿真器调试eCos系统,RedBoot集成的GDBStubs已经支持eCos的多线程调试,使用GDB命令infothreads就可以读取当前的线程状态。但是使用仿真器时,由于仿真器不......
  • Java多线程 ThreadPoolExecutor-RejectedExecutionHandler拒绝执行策略
    (目录)一、说明RejectedExecutionHandler当线程池已经被关闭,或者任务数超过maximumPoolSize+workQueue时执行拒绝策略ThreadPoolExecutor.AbortPolicy默认拒绝策略,丢......
  • linux 多线程 c++2
    为了在用线程分离的时候保证即使主线程退出了,子线程还能正常运行,可以使用pthread_exit(NULL)去退出主线程,这样地址空间还能正常存在线程分离是为了保证主线程不会被堵塞,还能......