ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

GIL 线程池 进程池 同步 异步 阻塞 非阻塞

2019-03-08 16:47:59  阅读:199  来源: 互联网

标签:__ task 阻塞 client 线程 print import GIL


1.GIL

  是一个全局解释器锁,是一种互斥锁
  为什么需要GIL锁:因为一个python.exe进程中只有一份解释器,如果这个进程开启了多个线程都要执行代码
    多线程之间要竞争解释器,一旦竞争就有可能出现问题
  带来的问题:同一时间只有一个线程可以访问解释器
  好处:保证了多线程的数据安全
  thread_safe 线程安全的 多个线程同时访问也不会出问题
  not thread_safe 非线程安全的多线程同时访问可能会出现问题(加锁)
  默认情况下一个进程只有一个线程是不会出现问题的 但是不要忘记还有GC线程
  一旦出现多线程就可能出问题,所以当初就简单粗暴的加上GIL锁

  那么多线程是不是完全没有意义
  由于有GIL的存在 即使有多个CUP 也不能真正的并行
  有三个任务 三个任务要并发执行使效率最高
  1.多进程
  2.同一个进程下多线程
  只有一个CUP
    如果三个任务都要等待IO
    如果是采用方案1:由于IO的时间较长 不仅不能提高效率反而无谓的增加了系统开销
    方案2更好
  有三个CUP
    如果是采用方案1 并且三个任务都没有IO操作:开启三个进程并行的来执行 效率更高
    如果是采用方案2 并且三个任务都没有IO操作:开三个线程 必须串行执行 所以效率比进程更低
    应用程序分为两种
1.IO密集 IO操作较多 纯计算较少 采用多线程

from multiprocessing import Process
from threading import Thread, enumerate, current_thread
import time


def task():
    with open('db', 'rt', encoding='utf-8')as f:
        f.read()


if __name__ == '__main__':
    start = time.time()
    # for i in range(100):
    #     Thread(target=task).start()
    #
    # for t in enumerate():
    #     if t != current_thread():
    #         t.join()
    ps = []
    for i in range(100):
        p = Process(target=task)
        p.start()
    for p in ps:
        p.join()
    print(time.time() - start)

 

2.计算密集型 计算操作较多 IO较少 采用多进程

from multiprocessing import Process
from threading import Thread, enumerate, current_thread
import time
import os


def task():
a = 1
for i in range(10000000):
a += i


if __name__ == '__main__':
start = time.time()
for i in range(10):
Thread(target=task).start()

for t in enumerate():
if t != current_thread():
t.join()
# ps = []
# for i in range(10):
# p = Process(target=task)
# p.start()
# ps.append(p)
# for p in ps:
# p.join()
print(time.time() - start)

 

 

应用场景:
  TCP程序 应该采用多线程
  纯计算 列入人脸识别 语音识别等 采用多进程
什么情况需要自己加锁 当多个线程需要共享一个不属于解释器的资源时 必须要自己加
不用加锁的例子:多个线程要并发修改某个变量数据

2.线程池 进程池

from concurrent.futures import ThreadPoolExecutor
import time
import threading


def task():
print('running.......')


pool = ThreadPoolExecutor(3)
pool.submit(task)
pool.submit(task)
pool.submit(task)
pool.submit(task)
print(threading.active_count())
print(threading.enumerate())


time.sleep(3)
print(threading.active_count())
print(threading.enumerate())


池就是容器
服务器不能无限的开线程,所以需要对线程数量加以控制,
线程池就帮我们封装了线程数量的控制 以及线程的创建 以及线程的创建 销毁 任务的分配
使用方法都一样
线程池再创建时不会立即开启线程
等到提交任务时 如果没有空闲线程 并且已存在的线程数量 小于最大值 开个新的
线程开启以后就不会再关闭了 直到进程全部关闭

3.同步 异步 阻塞 非阻塞
阻塞:
  程序运行过程中遇到IO操作 无法继续
非阻塞:
  程序正在运行中,并且没有遇到IO,即使遇到IO也不会阻塞,CPU不会切走
  指的是程序的执行的状态

同步:
  在发起任务后必须在原地等待 任务执行完毕 才能继续往下执行

def task():
for i in range(100000000):
pass


print('start')
task()
print('over')

异步:
  在发起任务后立即继续往下执行,不需要等待任务的执行结果

# def task():
# for i in range(100000000):
# pass
#
#
# print('start')
# task()
# print('over')
from concurrent.futures import ThreadPoolExecutor

pool = ThreadPoolExecutor()
import time


def task(num):
  time.sleep(0.5)
  print('run...')
  return num ** 2


ress = []
for i in range(1, 11):
res = pool.submit(task, i)
# res.result() # 该函数是阻塞函数 会一直等到任务执行完毕 导致程序串行执行
ress.append(res)

# 保证 当我们要获取的时候 所有任务都已经执行完毕
pool.shutdown(wait=True) # 该函数也是阻塞函数
# 等到全部完成在获取结果
for i in ress:
  print(i.result())

print('over')

指的是发起任务的方式
异步效率高于同步
发起异步任务的方式 就是线程和进程
同步和阻塞是完全不同的
阻塞一定是CUP已经切走了
同步虽然也会卡住 但是CUP没切走 还在你的进程中

 并发的TCP

import socket

from concurrent.futures import ProcessPoolExecutor
from multiprocessing import Process


def task(client):
    while True:
        data = client.recv(1024)
        print(data.decode('utf-8'))
        client.send(data.upper())


if __name__ == '__main__':
    server = socket.socket()
    server.bind(('127.0.0.1', 8888))
    server.listen()
    # 创建一个进程池
    pool = ProcessPoolExecutor(3)
    while True:
        client, address = server.accept()  # 三次握手
        # 控制链接数量 得用连接池
        # 开启一个进程来处理这个连接
        # t=Process(target=task,args=(client,))
        # t.start()
        # 现在将任务交到进程池中
        pool.submit(task, client)
server进程池
import socket

client = socket.socket()
client.connect(('127.0.0.1', 8888))
while True:
    msg = input(">>>:").strip()
    if not msg:
        continue
    client.send(msg.encode('utf-8'))
    print(client.recv(1024).decode('utf-8'))
client
import socket

from concurrent.futures import ThreadPoolExecutor
from threading import Thread


def task(client):
    while True:
        data = client.recv(1024)
        print(data.decode('utf-8'))
        client.send(data.upper())


if __name__ == '__main__':
    server = socket.socket()
    server.bind(('127.0.0.1', 8888))
    server.listen()
    # 创建一个线程池
    pool = ThreadPoolExecutor(3)
    while True:
        client, address = server.accept()  # 三次握手
        # 控制链接数量 得用连接池
        # 开启一个线程来处理这个连接
        # t=Process(target=task,args=(client,))
        # t.start()
        # 现在将任务交到线程池中
        pool.submit(task, client)
server线程池

 

标签:__,task,阻塞,client,线程,print,import,GIL
来源: https://www.cnblogs.com/ShenJunHui6/p/10496721.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有