长行 2023-05-07 08:09 采纳率: 100%
浏览 13
已结题

请问大家有推荐的 CPython 相关教程或书籍吗?

请问大家有推荐的 CPython 相关教程或书籍吗?我希望找一套讲解 Python 虚拟机和 Python 编译器源码的教程学习。

  • 写回答

1条回答 默认 最新

  • CSDN-Ada助手 CSDN-AI 官方账号 2023-05-07 10:02
    关注
    • 这个问题的回答你可以参考下: https://ask.csdn.net/questions/7426871
    • 你也可以参考下这篇文章:CPython的命令行与python文件的执行
    • 除此之外, 这篇博客: 面向 CPython GIL 的多线程编程要点中的 Python 的线程库锁 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
    • 我们再举个例子看看非原子操作下,怎么保证线程安全。

      >>> n = 0
      >>> def foo():
      ...     global n
      ...     n += 1
      ...
      >>> import dis
      >>> dis.dis(foo)
        3           0 LOAD_GLOBAL              0 (n)
                    3 LOAD_CONST               1 (1)
                    6 INPLACE_ADD
                    7 STORE_GLOBAL             0 (n)
                   10 LOAD_CONST               0 (None)
                   13 RETURN_VALUE
      

      代码编译后的字节码指令:

      1. 将全局变量 n 的值 load 到堆栈
      2. 将常数 1 的值 load 到堆栈
      3. 在堆栈顶部将两个数值相加
      4. 将相加结果存储回全局变量 n 的地址
      5. 将常数 0(None) 的值 load 到堆栈
      6. 从堆栈顶部返回常数 0 给函数调用者

      语句 n += 1 被编译成了前 4 个字节码,后两个字节码是 foo 函数的 return 操作,解释器自动添加。

      我们在上文提到,Python2 的线程每执行 1000 个字节码就会被动的让出 GIL。现在假如字节码指令 INPLACE_ADD 就是那第 1000 条指令,这时本应该继续执行 STORE_GLOBAL 0 (n) 存储到 n 地址的数据就被驻留在了堆栈中。如果同一时刻,变量 n 被别的处理器当前线程中的代码调用了。那么请问现在的 n 还是 +=1 之后的 n 吗?答案是此时的 n 发生了更新丢失,在两个当前线程中的 n 已经不是同一个 “n” 了。这就是上面我们提到过的内存可见性数据安全问题的又一个佐证。

      下面的代码正确输出为 100,但在 Python 多线程多处理器场景中,可能会得到 99 或 98 的结果。

      import threading
      
      n = 0
      threads = []
      
      
      def foo():
          global n
          n += 1
      
      
      for i in range(100):
          t = threading.Thread(target=foo)
          threads.append(t)
      
      
      for t in threads:
          t.start()
      
      
      for t in threads:
          t.join()
      
      
      print(n)
      

      此时,Python 程序员应该要想到使用 Python 线程库的锁来解决为。

      import threading
      
      n = 0
      lock = threading.Lock()
      threads = []
      
      
      def foo():
          global n
          with lock:
              n += 1
      
      
      for i in range(100):
          t = threading.Thread(target=foo)
          threads.append(t)
      
      
      for t in threads:
          t.start()
      
      
      for t in threads:
          t.join()
      
      
      print(n)
      

      显然,即便 Python 已经存在了 GIL,但依旧要求程序员坚持 “始终为共享可变状态的读写上锁”。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 5月15日
  • 已采纳回答 5月7日
  • 创建了问题 5月7日

悬赏问题

  • ¥15 微信会员卡等级和折扣规则
  • ¥15 微信公众平台自制会员卡可以通过收款码收款码收款进行自动积分吗
  • ¥15 随身WiFi网络灯亮但是没有网络,如何解决?
  • ¥15 gdf格式的脑电数据如何处理matlab
  • ¥20 重新写的代码替换了之后运行hbuliderx就这样了
  • ¥100 监控抖音用户作品更新可以微信公众号提醒
  • ¥15 UE5 如何可以不渲染HDRIBackdrop背景
  • ¥70 2048小游戏毕设项目
  • ¥20 mysql架构,按照姓名分表
  • ¥15 MATLAB实现区间[a,b]上的Gauss-Legendre积分