当前位置: 首页
AI教程
软件开发进阶技能:编程语言深度运用(三)

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

热心网友 时间:2026-06-07
转载

并发与异步编程模型利用多核提升性能,涉及线程与协程、异步模型从回调到async await的演进。多线程同步需用锁、原子操作或并发集合处理数据竞争,避免死锁需固定锁顺序或使用高级同步工具。

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

多核处理器已经成为现代计算机的标配,如何充分借助并发与并行来提升程序性能,成为开发者必须掌握的核心技能。但并发编程有一个显著特点:它既能带来性能提升,也可能引发诸多难题——数据竞争、死锁、线程安全,每一个都不容小觑。因此,深入理解一门语言的并发模型,才是安全高效编写并发程序的关键。

3.1 并发的基本概念:并行 vs 并发,线程 vs 协程

先来厘清并发与并行的区别。并发,是指多个任务在逻辑上“同时”进行,实际上是通过时间片轮转交替切换;并行,则是多个任务在物理上真正同时执行,这需要多核处理器的支持。打个比方:一个人轮流吃三碗饭是并发,三个人各自同时吃一碗才是并行。

那么线程和协程又有何不同?线程是操作系统调度的最小单位,切换成本大约在几微秒到几十微秒之间。而协程是由语言运行时在用户态调度的轻量级“线程”,切换成本低至纳秒级,创建几十万个协程也毫无压力。

image.png

3.2 异步编程模型:回调 → Promise → async/await 的演进

异步编程的核心在于:程序在等待I/O操作时,可以腾出手来处理其他任务,避免线程白白阻塞。掌握异步模型,是编写高响应、高吞吐应用的前提条件。

来看一个实际例子: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),这种写法读起来要友好得多。

再看看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 多线程同步:锁、原子操作、并发集合

一旦多个线程共享可变状态,同步机制就必须上场了。否则数据一致性将无从谈起。

以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则通过分段计数进一步降低竞争。进阶开发者会根据场景灵活选择最合适的方案。

再看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]
}

处理读多写少的场景时,RWMutex更为合适——它允许多个读操作并发执行,写操作则独占访问。

3.4 数据竞争与死锁的检测与避免

数据竞争的本质是:多个线程同时访问同一内存位置,且至少有一个是写操作,同时没有任何同步保护。Go语言内置了数据竞争检测器,只需在测试时加上 go test -race 就能直接定位问题。

而死锁,则是指两个或多个线程互相等待对方持有的锁,最终导致所有线程都无法继续执行。

来看一个经典的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
  • 使用超时尝试:Java中的tryLock(timeout),获取失败时释放已持有的锁,然后重试。
  • 减小锁粒度:采用并发集合(如ConcurrentHashMap)或无锁数据结构来替代粗粒度锁。
  • 使用更高级的同步工具:像java.util.concurrent包中的SemaphoreCountDownLatch等,比手动管理锁更加安全可靠。
来源:https://developer.aliyun.com/article/1739332

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
天学会AI应用开发上下文与RAG阶段性总结

天学会AI应用开发上下文与RAG阶段性总结

系统梳理了AI应用开发中的上下文与RAG核心概念。搭建Python3 10开发环境后,通过提示词工程管理历史对话,利用截断、摘要提取及离线大模型压缩上下文。RAG采用加载文档、分块、向量化、存入FAISS或Chroma库、检索五个步骤,中文场景推荐BGE-small嵌入模型,实战证明离线检索有效。

时间:2026-07-12 16:04
Yank Note系列14:如何与AI协作写文章

Yank Note系列14:如何与AI协作写文章

YankNote3 92 1发布,新增“审阅批注”和“编辑装订线”扩展,聚焦AI写作的人机协作循环。审阅批注将反馈绑定到选中文本,编辑装订线高亮显示修改行,帮助人看清AI改动。同时升级Markdown-it至14 3 0,优化中日韩文本渲染。

时间:2026-07-12 16:04
一文读懂MCP:让AI大模型万能插拔协议

一文读懂MCP:让AI大模型万能插拔协议

MCP(模型上下文协议)由Anthropic提出,为AI大模型提供通用接口标准,解决工具调用碎片化问题。采用Host Client Server架构,支持动态发现工具,通过stdio或HTTP通信,实现工具即插即用、跨语言调用和统一对接规范。

时间:2026-07-12 16:04
BeeWeave开源:为AI Agent打造越用越懂你的知识创作台

BeeWeave开源:为AI Agent打造越用越懂你的知识创作台

BeeWeave是一个Agent原生的知识创作台,通过workbench和vault双层结构实现素材获取、内容创作、知识沉淀与上下文复用的持续闭环。它支持多Agent共用同一套知识库,内置41个Skills,采用MIT开源协议,旨在解决跨会话知识丢失问题。

时间:2026-07-12 15:04
AI闭环工程师自动推进工程任务

AI闭环工程师自动推进工程任务

LoopEngineer是一种将AI嵌入可执行、可验证、可持续迭代的工作循环中的工程协作方式。通过触发器、上下文、工具和验证机制,AI在循环中自动分析、执行、验证并调整,直至任务完成或需人工介入,实现复杂任务的可观察、可审计、可批准的分段自动化。

时间:2026-07-12 15:04
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 热门数据榜