分类: 软件

  • 🐍 Python多进程:在Windows与Linux间的迷雾

    在编程的世界里,Python因其简洁的语法和强大的功能深受开发者的喜爱。然而,当我们谈及多进程时,Windows和Linux就像两位性格截然不同的角色,各自有着独特的表现方式。今天,我们将揭开这一神秘面纱,深入探讨它们之间的区别,以及如何在这两者之间架起桥梁,避免潜在的错误。

    🚀 简单函数的启动与阻塞

    首先,我们来看一个简单的多进程示例。以下代码展示了如何使用多进程运行一个简单函数,而不会阻塞主程序:

    import multiprocessing as mp
    from time import sleep
    
    def simple_func():
        print('开始 simple func')
        sleep(1)
        print('结束 simple func')
    
    if __name__ == '__main__':
        p = mp.Process(target=simple_func)
        p.start()
        print('等待 simple_func')
        p.join()

    当我们运行这段代码时,输出符合我们的预期,显示了主程序在等待子进程的消息。

    🕵️‍♂️ Windows与Linux的输出对比

    接下来,再来看一段稍微复杂一点的代码:

    import multiprocessing as mp
    from time import sleep
    
    print('定义 simple_func 之前')
    
    def simple_func():
        print('开始 simple func')
        sleep(1)
        print('结束 simple func')
    
    if __name__ == '__main__':
        p = mp.Process(target=simple_func)
        p.start()
        print('等待 simple_func')
        p.join()

    在Windows上运行时,你会看到以下输出:

    定义 simple_func 之前
    等待 simple_func
    定义 simple_func 之前
    开始 simple func
    结束 simple func

    而在Linux上,输出则是:

    定义 simple_func 之前
    等待 simple_func
    开始 simple func
    结束 simple func

    这里的差异源于操作系统对进程的处理方式。在Linux中,子进程通过fork生成,继承了父进程的内存状态。而在Windows上,进程是通过spawn生成的,这意味着新的解释器启动并重新运行代码。

    ⚠️ 必须的if name == ‘main

    在Windows上,如果我们没有使用if __name__ == '__main__',将会遭遇一个看似无尽的错误信息,最终以RuntimeError告终。这个错误暗示用户,当前进程尚未完成引导阶段,试图启动新进程是行不通的。

    在Linux上,虽然不会出现这个问题,但为了代码的可移植性,始终将其包含在内是个明智的选择。

    🎲 随机数的奇妙之旅

    再让我们看看一个涉及随机数的例子:

    import multiprocessing as mp
    import random
    
    val = random.random()
    
    def simple_func():
        print(val)
    
    if __name__ == '__main__':
        print('multiprocessing之前:')
        simple_func()
        print('multiprocessing之后:')
        p = mp.Process(target=simple_func)
        p.start()
        p.join()

    在Windows上,输出的两个值可能会有所不同,而在Linux上,两个值将保持一致。这是因为Windows和Linux在处理全局变量时的策略不同。

    🔄 从Linux到Windows的迁移

    如何将Linux上的代码迁移到Windows上呢?看看这个稍微复杂的示例:

    import multiprocessing as mp
    
    class MyClass:
        def __init__(self, i):
            self.i = i
    
        def simple_method(self):
            print('这是一个简单函数')
            print(f'保存的值是: {self.i}')
    
        def mp_simple_method(self):
            self.p = mp.Process(target=self.simple_method)
            self.p.start()
    
        def wait(self):
            self.p.join()
    
    if __name__ == '__main__':
        my_class = MyClass(1)
        my_class.mp_simple_method()
        my_class.wait()

    这段代码在Windows和Linux上均可正常运行。然而,如果我们尝试进行一些稍微复杂的操作,比如从文件中写入或读取数据时,就会出现问题。以下是一个例子:

    import multiprocessing as mp
    
    class MyClass:
        def __init__(self, i):
            self.i = i
            self.file = open(f'{i}.txt', 'w')
    
        def simple_method(self):
            print('这是一个简单函数')
            print(f'保存的值是: {self.i}')
    
        def mp_simple_method(self):
            self.p = mp.Process(target=self.simple_method)
            self.p.start()
    
        def wait(self):
            self.p.join()
            self.file.close()
    
    if __name__ == '__main__':
        my_class = MyClass(1)
        my_class.mp_simple_method()
        my_class.wait()

    在Linux上,这段代码可以正常工作。然而,在Windows上,就会抛出一个TypeError,提示无法序列化'_io.TextIOWrapper'对象。原因在于,Windows的spawn机制需要将整个对象进行pickle处理,而文件对象是无法被pickle的。

    🛠️ 解决方案:变更进程启动方式

    虽然在Windows上无法改变进程启动方式,但在Linux上可以。我们可以通过以下代码来设定启动方式:

    if __name__ == '__main__':
        mp.set_start_method('spawn')
        my_class = MyClass(1)
        my_class.mp_simple_method()
        my_class.wait()

    这样做将使得代码在Linux和Windows上产生相同的错误,从而保持结果的一致性。

    ⚖️ 设计任务的合理性

    最后,让我们回顾一下多进程的速度问题。虽然多进程能够利用多个CPU加速程序,但是启动子进程的开销也不容忽视。在Windows和Mac上,Python需要对对象进行pickle处理,这可能抵消在独立进程上运行的好处。如果每个进程任务都很短,可能会导致CPU的浪费。因此,在设计多进程任务时,应合理评估任务的设计,确保子进程的运行时间不会过短。

    📚 小结

    在多进程处理上,Windows和Linux的差异就像两种不同的饮品,虽然各有千秋,却也各有各的调制方式。理解这些差异并灵活应对,将帮助我们在跨平台开发中游刃有余。

    参考文献

    1. Sprite. (2023). Python多进程在Windows 和 Linux 的区别. IT碎碎念.
    2. Python官方文档. (2023). Multiprocessing — Process-based parallelism.
    3. Stack Overflow. (2023). Python multiprocessing differences between Windows and Linux.
    4. Real Python. (2023). Understanding Python’s Multiprocessing Module.
    5. GeeksforGeeks. (2023). Multiprocessing in Python: A Guide.

  • Merkle DAGs:构建分布式网络的基石 🏗️

    在当今数字化的世界中,数据的共享与管理显得尤为重要。Merkle DAG(有向无环图)不仅提供了一种灵活的方式来建模和共享数据,更是构成了许多分布式网络和系统的基础。从版本控制系统到区块链技术,Merkle DAG的应用遍及多个领域。

    Merkle DAG的多重应用 🌍

    Merkle DAG作为一种基础构件,广泛应用于以下项目中:

    1. 版本控制系统(如Git):利用Merkle DAG来追踪源代码的变化,确保每次提交的历史记录都能被高效存储和检索。
    2. 区块链技术(如Ethereum):在区块链中,Merkle DAG用于构建区块和交易的结构,使得数据的验证和追溯变得更加简单和安全。
    3. 去中心化网络协议(如IPFS):IPFS使用Merkle DAG来实现内容寻址,确保数据在网络中的有效分发。
    4. 分布式存储网络(如Filecoin):通过Merkle DAG,Filecoin能够高效地管理和存储大规模的数据集。

    这种广泛的应用表明,Merkle DAG不仅仅是技术的实现,它们还可以作为不同项目之间的共同沟通基础。

    IPLD:构建互联数据生态系统的桥梁 🌉

    为了实现Merkle DAG在不同项目之间的互通,InterPlanetary Linked Data(IPLD)项目正在开发基于Merkle DAG的数据格式及其正式描述。这种生态系统旨在支持广泛的数据交换。

    • CIDs(内容标识符):作为内容寻址的共同语言,CIDs为每个数据提供了唯一的全球地址。
    • IPLD:定义了常见的数据格式,作为结构化和交流内容地址数据的正式架构。

    通过解析IPLD数据和CIDs,系统能够轻松引用来自其他系统的内容。例如,Filecoin的交易可以引用IPFS中的数据块,或者区块链上的智能合约可以引用特定的Git提交。

    全球互联数据生态系统的愿景 🌐

    Merkle DAG和IPLD共同构成了一个全球互联的、相互理解的数据生态系统。它们的结合使得跨平台的数据共享变得简单而高效,从而推动了去中心化网络的进一步发展。

    结论 🎊

    Merkle DAG作为数据管理的基础构件,不仅为现代技术提供了支持,更为未来的去中心化网络铺平了道路。随着IPLD的进一步发展,我们可以期待一个更加连接和互通的数字世界。

    参考文献 📚

    1. ProtoSchool. (n.d.). IPLD Tutorial | Merkle DAGs: Structuring Data for the Distributed Web (Lesson 8). Retrieved from ProtoSchool.

    如果你对Merkle DAG及其在去中心化网络中的应用还有任何疑问,欢迎随时提问!

人生梦想 - 关注前沿的计算机技术 acejoy.com 🐾 步子哥の博客 🐾 背多分论坛 🐾 知差(chai)网
快取状态: No
内存使用量: 11.2836 MB
资料库查询次数: 80
页面产生时间: 1.078 (秒)