软件开发进阶技能之编程语言深度运用(三)

简介: 教程来源 https://bslm2020.com/ 本节深入解析并发与异步编程核心:厘清并行/并发、线程/协程本质差异;梳理回调→Promise→async/await演进脉络;详解锁、原子操作、RWMutex等同步机制;剖析数据竞争与死锁成因及规避策略,助开发者安全高效驾驭多核时代。

第三部分:并发与异步编程模型 —— 驾驭多核时代的力量

现代计算机多核处理器普及,充分利用并发和并行是提升程序性能的关键。但并发编程也带来了数据竞争、死锁、线程安全等复杂问题。深度掌握语言的并发模型,能够安全高效地编写并发程序。

3.1 并发的基本概念:并行 vs 并发,线程 vs 协程
并发:多个任务在逻辑上同时执行(交替进行)。

并行:多个任务在物理上同时执行(需要多核)。

线程:操作系统调度的最小单位,切换成本较高(几微秒到几十微秒)。

协程:用户态轻量级线程,由语言运行时调度,切换成本极低(纳秒级),可以创建数十万个。

不同语言提供的并发原语:
image.png
3.2 异步编程模型:回调 → Promise → async/await 的演进
异步编程允许程序在等待I/O时执行其他任务,避免线程阻塞。理解异步模型是编写高响应、高吞吐应用的基础。

示例15:JavaScript的Promise链与async/await

// 模拟异步操作
function fetchUser(id) {
    return new Promise(resolve => {
        setTimeout(() => resolve({ id, name: `User${id}` }), 100);
    });
}

function fetchPosts(userId) {
    return new Promise(resolve => {
        setTimeout(() => resolve([`Post1 by ${userId}`, `Post2 by ${userId}`]), 100);
    });
}

// Promise链式调用
fetchUser(1)
    .then(user => {
        console.log(user.name);
        return fetchPosts(user.id);
    })
    .then(posts => {
        console.log(posts);
    })
    .catch(err => console.error(err));

// async/await 更清晰的写法
async function displayUserContent(id) {
    try {
        const user = await fetchUser(id);
        console.log(user.name);
        const posts = await fetchPosts(user.id);
        console.log(posts);
    } catch (err) {
        console.error(err);
    }
}
displayUserContent(2);

深度解释:async函数返回一个Promise,await会暂停当前函数的执行,直到Promise完成,但不会阻塞事件循环。这比回调地狱(Callback Hell)可读性高得多。

示例16:Python的asyncio实现并发网络请求

import asyncio
import aiohttp

async def fetch_url(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    urls = [
        'http://example.com',
        'http://example.org',
        'http://example.net',
    ]
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_url(session, url) for url in urls]
        results = await asyncio.gather(*tasks)
        for url, html in zip(urls, results):
            print(f"{url}: {len(html)} bytes")

asyncio.run(main())

关键点:asyncio.gather并发执行多个协程。在等待网络响应时,事件循环可以切换到其他协程,实现高效I/O并发。

3.3 多线程同步:锁、原子操作、并发集合
当多个线程共享可变状态时,必须使用同步机制来保证数据一致性。

示例17:Java中的线程安全计数器比较

// 非线程安全
class UnsafeCounter {
    private int count = 0;
    public void increment() { count++; }  // 多线程下丢失更新
    public int get() { return count; }
}

// 使用synchronized
class SynchronizedCounter {
    private int count = 0;
    public synchronized void increment() { count++; }
    public synchronized int get() { return count; }
}

// 使用AtomicInteger(无锁CAS)
import java.util.concurrent.atomic.AtomicInteger;
class AtomicCounter {
    private AtomicInteger count = new AtomicInteger(0);
    public void increment() { count.incrementAndGet(); }
    public int get() { return count.get(); }
}

// 使用LongAdder(高并发下更好)
import java.util.concurrent.atomic.LongAdder;
class AdderCounter {
    private LongAdder count = new LongAdder();
    public void increment() { count.increment(); }
    public long get() { return count.sum(); }
}

性能对比:synchronized适合低竞争场景;AtomicInteger基于CAS,没有锁的开销,但在高竞争下可能自旋;LongAdder通过分段计数进一步减少竞争。进阶开发者会根据场景选择合适的同步工具。

示例18:Go的Mutex和RWMutex

type SafeCounter struct {
    mu sync.Mutex
    m  map[string]int
}

func (c *SafeCounter) Inc(key string) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.m[key]++
}

func (c *SafeCounter) Value(key string) int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.m[key]
}

// 读多写少场景使用RWMutex,允许并发读
type SafeMap struct {
    mu sync.RWMutex
    m  map[string]string
}

func (s *SafeMap) Get(key string) string {
    s.mu.RLock()
    defer s.mu.RUnlock()
    return s.m[key]
}

3.4 数据竞争与死锁的检测与避免
数据竞争:多个线程同时访问同一内存位置,至少有一个是写操作,且没有同步。Go语言内置了数据竞争检测器:go test -race。

死锁:两个或多个线程互相等待对方持有的锁,导致永久阻塞。

示例19:Java死锁示例及解决方法

public class DeadlockDemo {
    private final Object lock1 = new Object();
    private final Object lock2 = new Object();

    public void method1() {
        synchronized(lock1) {
            sleep(100);  // 模拟工作
            synchronized(lock2) {
                System.out.println("method1 done");
            }
        }
    }

    public void method2() {
        synchronized(lock2) {
            sleep(100);
            synchronized(lock1) {
                System.out.println("method2 done");
            }
        }
    }

    private void sleep(int ms) { try { Thread.sleep(ms); } catch(Exception e) {} }

    public static void main(String[] args) {
        DeadlockDemo demo = new DeadlockDemo();
        new Thread(demo::method1).start();
        new Thread(demo::method2).start();
    }
}

避免死锁的原则:

固定锁顺序:总是以相同的顺序获取锁。例如,总是先获取lock1再获取lock2。

使用超时尝试:tryLock(timeout)(Java),如果获取失败则释放已持有的锁并重试。

减少锁粒度:使用并发集合(ConcurrentHashMap)或无锁数据结构。

使用更高级的同步工具:如java.util.concurrent的Semaphore、CountDownLatch等。
来源:
https://zlpow.cn/

相关文章
|
22天前
|
XML 前端开发 程序员
初级程序员必备的十大技能之 API 接口与前后端联调(一)
教程来源 http://qeext.cn/ 本文系统讲解API设计规范(RESTful/GraphQL)、HTTP协议核心(方法、状态码、头信息)、前后端联调流程及调试工具,助你打造标准化、高可用接口,打破前后端协作孤岛。
|
22天前
|
存储 程序员 Linux
初级程序员必备的十大技能之 Git 版本控制(一)
教程来源 http://xcfsr.cn Git是程序员的“后悔药”与“时光机”:可随时回退错误修改、隔离并行开发、一键恢复稳定版本。作为分布式版本控制系统,它本地全量存储、离线可用、安全可靠,支撑全球90%以上团队高效协作。
|
8天前
|
Ubuntu Linux KVM
虚拟机搭建教程(二)
教程来源 https://zlpow.cn/ 本文详解Windows、Linux三大平台虚拟化实战:Windows下用VMware安装Ubuntu 24.04(含Tools与快照),VirtualBox部署CentOS Stream 9;Linux主机通过KVM命令行及virt-manager搭建高性能虚拟机,覆盖配置、联网、增强工具与管理全流程。
|
8天前
|
SQL 网络协议 NoSQL
软件开发新手入门五大核心技能之计算机基础常识(五)
教程来源 http://vbzcj.cn/ 本章系统讲解网络与数据库核心知识:涵盖OSI/TCP/IP模型、IP/端口、TCP三次握手/四次挥手、HTTP协议、DNS解析;以及SQL基础、索引优化、ACID事务、NoSQL(如Redis)等,理论结合Python实战示例。
|
8天前
|
存储 缓存 固态存储
软件开发新手入门五大核心技能之计算机基础常识(一)
教程来源 http://oieaw.cn/ 本文以“内功”喻计算机基础,系统讲解CPU、内存、存储等硬件原理及冯·诺依曼体系,涵盖指令执行、缓存机制、内存布局、I/O特性等核心知识,并辅以可运行代码与典型问题分析,助程序员夯实底层认知,提升性能优化与系统设计能力。
|
8天前
|
存储 Linux KVM
虚拟机使用教程大全(三)
教程来源 https://qcycj.cn/ 快照是虚拟机的“时间胶囊”,可保存任意时刻的完整状态(含内存与磁盘),支持快速回滚、实验保护与克隆部署。本文详解VMware、VirtualBox、KVM三大平台快照创建/恢复/删除操作,强调其非备份本质、性能影响及3–5个快照的黄金管理实践。
|
23小时前
|
自然语言处理 JavaScript 前端开发
软件开发进阶技能之编程语言深度运用(五)
教程来源 https://tjxhrt.cn/ 本节深入函数式编程核心特性:高阶函数与闭包、不可变数据结构、纯函数设计及惰性求值。通过多语言示例(JS/Java/Python),讲解如何提升代码简洁性、可测试性与并发安全性,让数据流更清晰可控。
|
23小时前
|
存储 Java 程序员
软件开发进阶技能之编程语言深度运用(二)
教程来源 https://tdfr.cn/ 本节深入解析内存管理核心:栈/堆机制、值/引用类型差异、GC原理与调优、内存泄漏防控及对象池复用技术,覆盖C/C++、Java、Go、Python、C#、JavaScript等主流语言实践,助你写出高性能、低开销、高稳定性的代码。
|
8天前
|
JavaScript Java Python
软件开发新手入门五大核心技能之基础编程能力(三)
教程来源 http://yyvgt.cn/ 本章深入讲解函数与模块化编程:涵盖Python/Java/JS中函数定义、参数传递(默认/关键字/可变参数)、作用域与闭包、递归原理及优化技巧(汉诺塔、备忘录、尾递归),强调代码复用与健壮性设计。
|
8天前
|
消息中间件 存储 资源调度
软件开发新手入门五大核心技能之计算机基础常识(四)
教程来源 http://uklgy.cn/ 本章介绍操作系统核心机制:进程/线程模型、IPC通信方式;并发控制中的竞态条件、锁与死锁;虚拟内存与分页机制;文件系统结构及权限管理。辅以Java、Python、C语言实例,深入浅出解析资源调度与内存管理原理。