首页 > 其他分享 >互斥锁及线程相关知识

互斥锁及线程相关知识

时间:2022-11-21 22:11:54浏览次数:46  
标签:__ 锁及 互斥 线程 print import data

今日内容概要

  • 多进程实现TCP服务端并发
  • 互斥锁
  • 线程相关基础知识
  • GIL全局解释器锁
  • event事件
  • 进程池与线程池
  • 协程

今日内容详细

多进程实现TCP服务端并发

多进程实现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)
        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()

互斥锁

互斥锁可以实现将多进程的并发转换为串行,互斥锁会降低程序运行的效率,但是可以提高数据操作的安全性。

互斥锁添加位置一般为数据操作之前,这样能够降低对程序运行效率的影响。

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()

死锁现象

当一个线程内有多个互斥锁时,可能会出现死锁现象,其原因是互斥锁没有及时释放,导致锁同时占用。

信号量

在python并发编程中信号量相当于多把互斥锁。

from threading import Thread, Lock, Semaphore

sp = Semaphore(5) # 一次生成5把互斥锁

线程相关基础知识

线程概念相关

进程本质是申请一块内存空间,然后在其中执行需要执行的代码,线程则是进程中执行的某一段代码。

如果说进程是一座工厂,则线程则是工厂内部的流水线。

每个进程拥有属于自己的一个名称空间,其内部的线程可以调用名称空间中的所有名称。

创建新的线程

线程相关模块与进程类似,使用方法也类似。

from threading import Thread

常用内置方法

join() 使子线程与主线程时间同步。

current_thread() 查看当前线程的名称。

active_count() 查看当前进程内有多少个活跃的线程。

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.

①解释器类型:编写解释器代码所用的语言决定了解释器类型,GIL全局锁仅存在于CPython中。

②互斥锁:GIL全局解释器锁本质也是互斥锁,它的存在使CPython解释器中没有实质上的多线程。

③CPython中数据不安全,其原因为其内部的数据管理方式即垃圾回收机制。

GIL与普通互斥锁

GIL只能够确保同进程内多线程数据不会被垃圾回收机制弄乱,并不能确保程序里面的数据是否安全。GIL只针对线程执行生效,而普通互斥锁可以增加数据操作的安全性。

event事件

event事件对象相当于一个标志,初始为False,通过set使其变为True,通过wait使进程在标志为True之前阻塞。

from threading import Thread, Event

event = Event()
event.set()
event.wait()

进程池与线程池

因为硬件的发展赶不上软件,物理极限的存在使我们在编写代码的过程中不能无限制的创建进程或者线程,进程或线程过多可能会导致计算机奔溃。

进程池与线程池通过事先创建固定数量的任务量,后续只能使用事先创建的任务执行来保证计算机硬件的安全。

from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
import os
import time
import random
from threading import current_thread

# 1.产生含有固定数量线程的线程池
# pool = ThreadPoolExecutor(10)
pool = ProcessPoolExecutor(5)


def task(n):
    print('task is running')
    # time.sleep(random.randint(1, 3))
    # print('task is over', n, current_thread().name)
    # print('task is over', os.getpid())
    return '我是task函数的返回值'


def func(*args, **kwargs):
    print('from func')

if __name__ == '__main__':
    # 2.将任务提交给线程池即可
    for i in range(20):
        # res = pool.submit(task, 123)  # 朝线程池提交任务
        # print(res.result())  # 不能直接获取
        # pool.submit(task, 123).add_done_callback(func)

协程

协程主要是为了实现单线程下的并发,并不是一个实际存在的概念。其原理是在代码层面欺骗CPU,让CPU觉得我们的代码里面没有IO操作,实际上IO操作被我们自己写的代码检测,一旦有立刻让代码执行别的。

协程的实现主要通过gevent模块。

import time
from gevent import monkey;

monkey.patch_all()  # 固定编写 用于检测所有的IO操作(猴子补丁)
from gevent import spawn


def func1():
    print('func1 running')
    time.sleep(3)
    print('func1 over')


def func2():
    print('func2 running')
    time.sleep(5)
    print('func2 over')


if __name__ == '__main__':
    start_time = time.time()
    # func1()
    # func2()
    s1 = spawn(func1)  # 检测代码 一旦有IO自动切换(执行没有io的操作 变相的等待io结束)
    s2 = spawn(func2)
    s1.join()
    s2.join()
    print(time.time() - start_time)  # 8.01237154006958   协程 5.015487432479858

实例

import socket
from gevent import monkey;monkey.patch_all()  # 固定编写 用于检测所有的IO操作(猴子补丁)
from gevent import spawn


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


def get_server():
    server = socket.socket()
    server.bind(('127.0.0.1', 8080))
    server.listen(5)
    while True:
        sock, addr = server.accept()  # IO操作
        spawn(communication, sock)

s1 = spawn(get_server)
s1.join()

标签:__,锁及,互斥,线程,print,import,data
From: https://www.cnblogs.com/akazukis/p/16913537.html

相关文章

  • 互斥锁、线程、GIL全局解释器锁、进程池与线程池、协程
    内容详细多进程实现TCP服务端并发互斥锁代码实操线程理论创建线程的多种方式线程诸多特性GIL全局解释器锁验证GIL存在GIL与普通互斥锁的区别验......
  • 并发编程:多线程、GIL、协程
    目录一、多进程实现TCP服务器并发1.服务端2.客户端二、线程1.什么是线程2.进程与线程的关系3.创建线程的两种方式4.线程对象的其他方法5.同进程内多个线程数据共享三、互斥......
  • 线程、GIL全局解释器锁、进程池与线程池
    目录多进程实现TCP服务端并发互斥锁代码实操线程理论创建线程的两种方式多线程实现TCP服务端并发线程的诸多特性GIL全局解释器锁验证GIL的存在GIL与普通互斥锁python多线程......
  • 多线程/GIL全局锁
    目录线程理论创建线程的两种方式线程的诸多特性GIL全局解释器验证GIL存在同一个进程下多线程是否有优势死锁现象信号量Event事件线程理论进程进程其实是资源单位标......
  • 多进程实现TCP服务端并发、互斥锁代码实操、线程理论、创建线程的两种方式、线程的诸
    多进程实现TCP服务端并发importsocketfrommultiprocessingimportProcessdefget_server():server=socket.socket()server.bind(('127.0.0.1',8080))......
  • 互斥锁、死锁、信号量、线程、协程
    互斥锁、死锁、信号量、线程、协程目录互斥锁、死锁、信号量、线程、协程互斥锁互斥锁代码实操线程理论创建线程的两种方式线程的诸多特性GIL全局解释器锁验证GIL的存在GI......
  • 线程
    线程理论60年代,在OS中能拥有资源和独立运行的基本单位是进程,然而随着计算机技术的发展,进程出现了很多弊端,一是由于进程是资源拥有者,创建、撤消与切换存在较大的时空开......
  • 互斥锁 线程理论 GIL全局解释器锁 死锁现象 信号量 event事件 进程池与线程池 协程实
    目录互斥锁multiprocessingLock类锁的种类线程理论进程和线程对比开线程的两种方式(类似进程)方式1使用Thread()创建线程对象方式2重写Thread类run方法创建1000个进程vs......
  • 进程池、线程池、协程
    进程池、线程池、协程进程池与线程池硬件是有极限的,我们不可能一直在一台计算机上无限的创建新的进程和线程,虽然软件逻辑上我们可以无限的创建,但是一旦这么做了,我们的计......
  • 线程相关知识
    线程理论进程 进程其实是资源单位,表示一块内存空间线程 线程才是执行单位,表示真正的代码指令我们可以将进程比喻是车间,线程是车间里面的流水线一个进程内部至少含有......