<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Python on erpan&#39;s note</title>
    <link>https://940504.top/tags/python/</link>
    <description>Recent content in Python on erpan&#39;s note</description>
    <image>
      <title>erpan&#39;s note</title>
      <url>https://940504.top/%3Clink%20or%20path%20of%20image%20for%20opengraph,%20twitter-cards%3E</url>
      <link>https://940504.top/%3Clink%20or%20path%20of%20image%20for%20opengraph,%20twitter-cards%3E</link>
    </image>
    <generator>Hugo -- 0.154.5</generator>
    <language>en</language>
    <copyright>浙ICP备2021018236号-1</copyright>
    <lastBuildDate>Fri, 06 Mar 2020 14:43:33 +0800</lastBuildDate>
    <atom:link href="https://940504.top/tags/python/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>读redis-py客户端源码</title>
      <link>https://940504.top/posts/redis-py%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%BA%90%E7%A0%81%E5%88%9D%E8%AF%BB/</link>
      <pubDate>Fri, 06 Mar 2020 14:43:33 +0800</pubDate>
      <guid>https://940504.top/posts/redis-py%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%BA%90%E7%A0%81%E5%88%9D%E8%AF%BB/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;看别人的代码也是对自己思维和经验的学习丰富过程&lt;/p&gt;
&lt;p&gt;作为一个初学者，之前写过的代码量较少，很少涉及到完整的项目开发，看完redis-py库后，get到其中的&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;连接保活机制&lt;/li&gt;
&lt;li&gt;连接池的实现&lt;/li&gt;
&lt;li&gt;开辟buffer存入从socket接收来的数据及buffer管理&lt;/li&gt;
&lt;li&gt;熟悉了RESP协议&lt;/li&gt;
&lt;li&gt;多进程多线程的情况下，利用锁确保连接池数据结构安全&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我读的过程中觉得值得注意的是，&lt;code&gt;_in_use_connections&lt;/code&gt;使用集合结构；此连接池不是在初始化时创建好一定数量的tcp连接；其中用了两个互斥锁，一个保护连接池，一个保护多进程的池；较多的连接重连，确保连接可用&lt;/p&gt;
&lt;h2 id=&#34;执行过程&#34;&gt;执行过程&lt;/h2&gt;
&lt;p&gt;该库主要有Redis、Connection、ConnectionPool、PythonParse、SocketBuffer几个类，下面大概理了一下redis-py的执行过程&lt;/p&gt;
&lt;!-- TEASER_END --&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;开始使用redis-py客户端&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;class Redis实例化&lt;/p&gt;
&lt;p&gt;可以关注下面几个参数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;socket_timeout=None,&lt;/li&gt;
&lt;li&gt;socket_connect_timeout=None,&lt;/li&gt;
&lt;li&gt;socket_keepalive=None,&lt;/li&gt;
&lt;li&gt;socket_keepalive_options=None,&lt;/li&gt;
&lt;li&gt;connection_pool=None,&lt;/li&gt;
&lt;li&gt;retry_on_timeout=False,&lt;/li&gt;
&lt;li&gt;max_connections=None,&lt;/li&gt;
&lt;li&gt;single_connection_client=False, # 是否单个连接，不用连接池&lt;/li&gt;
&lt;li&gt;health_check_interval=0,&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;class ConnectionPool连接池初始化&lt;code&gt;ConnectionPool()&lt;/code&gt;，此时尚未创建连接&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; # 此处定义连接池最大连接数
 max_connections = max_connections or 2 ** 31

 # fork_safe，在_checkpid()方法中用到，保护临界区的锁。这个锁是在进程id改变时获得的。比如fork出一个子进程后，子进程id和池对象中保存的id不一致，那么子进程中的多个线程都可能会先获取此锁，第一个获得锁的线程将重置此池的数据结构并最终释放锁对象，后续的线程再执行时，pid已于子线程池中的pid熟悉一致，不再做其他操作，在下面也会有提到
 self._fork_lock = threading.Lock()

 # 定义了并初始化已创建连接数、使用中的链接、可用的连接等数据结构
 self._lock = threading.Lock()
 self._created_connections = 0
 self._available_connections = []
 self._in_use_connections = set()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意此处&lt;code&gt;_in_use_connections&lt;/code&gt;使用了集合存储池中的连接对象，这个与python数据类型时间复杂度有关，可&lt;a href=&#34;https://wiki.python.org/moin/TimeComplexity&#34;&gt;点此参考官网&lt;/a&gt;，集合的内部实现与字典极为相似，此集合对象只用到两个操作，&lt;code&gt;add&lt;/code&gt;和&lt;code&gt;remove&lt;/code&gt;，时间复杂度均为O(1)，（有误烦请指正🤡🤡🤡）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;初始化Redis-Client状态信息完毕，此时还没有任何连接被创建&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;假设开始执行 &lt;code&gt;r.set(&#39;foo&#39;, &#39;baiqi&#39;)&lt;/code&gt;，此方法返回&lt;code&gt;r.excute_command()&lt;/code&gt;的结果&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;首先尝试从池中获取一个Connection对象 &lt;code&gt;pool.get_connection(command_name, **options)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;获取时得先执行下&lt;code&gt;_checkpid()&lt;/code&gt;方法，再执行&lt;code&gt;get_connection()&lt;/code&gt;&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
