Jiahong的个人博客

凡事预则立不预则废


  • Home

  • Tags

  • Archives

  • Search

Python——并发模型

Posted on 2018-10-05

本文介绍Python中的并发机制,并给出一种最简洁的Python并发库


使用协程(yield语句)

  • 实现随时暂停和开始
  • 完全串行的操作,无法实现时间上的并行,这里指的是不能同时进行某个操作
  • 与Go语言的协程不同,Python的协程更像是一个“生成器”

使用线程

  • 参考threading模块实现自己的线程

使用concurrent.futures

实现线程池模型

  • 实现一般的线程池模型,代码如下,关键代码仅仅两行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import time
    from concurrent import futures

    def sleep_one_second(key):
    time.sleep(1)
    return "[%s]Done" % key

    ml = "ABCDEFGHIJ"
    with futures.ThreadPoolExecutor(10) as executor:
    res = executor.map(sleep_one_second, ml)

    print([r for r in res])
  • 上面的代码可以在一秒内执行完成,因为共有10个线程并发

  • 在实现爬虫程序时,如果需要爬取的某些数据是相对独立的,那么我们完全可以用线程池实现,而不用使用复杂的线程模块*

实现进程池模型

  • 仅仅需要修改futures.ThreadPoolExecutor为futures.ProcessPoolExecutor即可
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import time
    from concurrent import futures

    def sleep_one_second(key):
    time.sleep(1)
    return "[%s]Done" % key

    ml = "ABCDEFGHIJ"
    with futures.ProcessPoolExecutor(10) as executor:
    res = executor.map(sleep_one_second, ml)

    print([r for r in res])

进程与线程内存区别

对全局变量的访问对比
  • 线程:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from concurrent import futures
    global_list = []

    def test_futures(range_num):
    global_list.append(range_num)
    print global_list
    return range_num

    with futures.ThreadPoolExecutor(8) as executor:
    res = executor.map(test_futures, range(10))

    print "the final global_list: %s" % global_list
    • 上面的代码输出如下:

      [0]
      [0, [10, 2]
      , 1[0, 1, 2, , 32]
      , 3, [04, 1], 2, 3, 4
      [0, , 5]
      1, [0, 21, 2, [3, , 3, 044, , 51, , 6, , 75]
      2, [0, 1, 63, 7, , 2, 3[40, , 8, , 4, 9, 155, , 6, 2]6, , 7
      , 8, 7, 9, ]3
      8, 4, , 59, 6, ]
      7, 8, 9]
      the final global_list: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      the results: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

  • 进程:

from concurrent import futures
global_list = []

def test_futures(range_num):
    global_list.append(range_num)
    print global_list
    return range_num

with futures.ProcessPoolExecutor(8) as executor:
    res = executor.map(test_futures, range(10))

print "the final global_list: %s" % global_list
    • 上面的代码输出如下:

      [0]
      [1]
      [2]
      [3]
      [0, 4]
      [5]
      [6]
      [7]
      [1, 8]
      [2, 9]
      the final global_list: []
      the results: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

  • 原因分析

    • 线程之间共享地址空间,所以所有的线程线程访问同一个全局共享变量
    • 进程之间不共享地址空间,所以不同进程访问不同共享变量
    • 在程序中Process之间不共享地址空间,但是futures.ProcessPoolExecutor(max_workers)任务分配时受限与参数max_workers的影响,所以可以预估本地机器最多开启max_workers个进程,同一进程中地址空间共享,所以会有部分任务被分配给同一进程的不同线程,从而出现部分共享变量被不同任务访问到
    • 总结:
      • futures.ThreadPoolExecutor单进程多线程中全局变量共享
      • futures.ProcessPoolExecutor多进程多线程中每个进程内部的线程全局变量共享
      • 不同进程之间即使时全局变量也不能共享

Python中进程 VS 线程

  • Python中由于全局解释器锁(GIL)的存在,同一进程中的所有线程使用同一个解释器对象,所以它们无法真正实现并行
  • 所以在想要充分利用多核的时候,需要选择使用多进程
  • 更多信息参考Process和Thread分析

Matplotlib——各种参数的一般含义总结

Posted on 2018-10-05

Matplotlib中有很多画图函数,画图时又有很多参数,本文从一般性的角度说明每个参数的一般含义


loc

  • 这个参数一般是指明图标的位置
    1
    plt.legend(loc='upper left')

MySQL——数据库导入导出

Posted on 2018-10-04

参考博客: https://blog.csdn.net/u013626215/article/details/88548342


从MySQL中导出数据库信息

  • 导出所有表结构

    1
    mysqldump -h [host_ip] -u [user_name] -p -d [db_name] > [file_name]
  • 导出所有表结构和数据

    1
    mysqldump -h [host_ip] -u [user_name] -p [db_name] > [file_name]
  • 导出某一张表结构

    1
    mysqldump -h [host_ip] -u [user_name] -p -d [db_name] [table_name] > [file_name]
  • 导出某一张表结构和数据

    1
    mysqldump -h [host_ip] -u [user_name] -p [db_name] [table_name] > [file_name]

导入数据库到MySQL

  • 登录数据库

    1
    mysql -h [host_ip] -u [user_name] -p
  • 执行导入命令

    1
    source [file_name]

注意:数据导入需要提前创建数据库

Python——抽象类和继承与Java的不同点

Posted on 2018-10-03

Python也开始支持抽象类和多态了,但是Python的继承与Java有很多不同的地方


Python只有私有属性

(双下划线__属性)和公有属性(默认属性),没有protected属性

  • 解决方案是Python提出命名时单下划线的属性为protected属性
    • 但是这只是一种口头约定,Python解释器并不做强制处理
  • 模块中的函数如果是单下划线开头的,那么该函数属于当前模块保护的
    • 此时某些IDE,比如Idea能够给出提示,但是用户仍可访问
    • 编程时建议将模块中不被调用的文件定义为_开头的,这样可以提示自己和别人当前函数不会在模块外被调用

Python类属性定义

属性定义在__init__函数中才能在对象中通过__dict__属性读取到


Python支持虚拟继承

可以欺骗编译器,不用真正实现虚拟基类的所有接口


都是强类型语言

这是他们的相同点,但我觉得写在这里是必要的


方法类型不同

  • Java中有一般方法(实例方法),静态方法(static类名和对象均可直接调用)两种
    • Java中这两种方法也都可以被继承和隐藏,而不能被重写(隐藏的意思时换成对应的父类指针还能访问到父类的静态属性和方法)
  • Python中有一般方法(实例方法),静态方法(@staticmethod类名和对象均可直接调用)和类方法@classmethod
    • 对@staticmethod方法的理解是,该方法与类密切相关,但是不需要访问这个类
    • Python的@staticmethod和@classmethod方法调用方式一样,唯一的区别在于@classmethod方法第一个参数必须是当前类(一般命名为cls)
    • Python中的这三种方法都可以被继承和重写

函数定义

  • 三种函数, 普通函数(实例函数), 类函数(classmethod), 静态函数(staticmethod)

普通函数

  • 无需任何装饰器
  • 无论如何定义,函数的第一个参数都会被当成实例对象本身(一般用self)

类函数

  • 装饰器 @classmethod
  • 无论如何定义,函数的第一个参数都会被当成实例对象本身(一般用cls)

静态函数

  • 装饰器 @staticmethod
  • 所有参数都是函数所有,不被占用

Python——Copy-and-Deepcopy

Posted on 2018-10-02

deepcopy与copy的本质区别——是否为可变对象创建新的对象(内存空间)
以下图片截取自Python Tutorial


代码片段一

  • 可变对象list中包含着可变list和不可变对象tuple, 且tuple中不包含可变对象
    1
    2
    3
    4
    5
    import copy
    l1 = [3, [66, 55, 44], (7, 8, 9)]
    l2 = list(l1) # <==> l2 = copy.copy(l1)
    # <==> l2 = l1[:]
    l3 = copy.deepcopy(l1)

代码片段二

  • 可变对象list中包含着可变list和不可变对象tuple, 且tuple中包含可变对象list
    1
    2
    3
    4
    5
    import copy
    l1 = [3, [66, 55, 44], (7, 8, [1, 2])]
    l2 = list(l1) # <==> l2 = copy.copy(l1)
    # <==> l2 = l1[:]
    l3 = copy.deepcopy(l1)

代码片段三

  • 不可变对象中包含可变对象
  • 值得强调的是,copy复制tuple时,不会像list那样直接创建新对象,无论tuple中是否有可变对象*
  • 除非包含不可变对象,否则deepcopy复制tuple时也不会创建新对象*
    1
    2
    3
    4
    5
    6
    7
    import copy
    t1 = (3, [66, 55, 44], (7, 8, [1, 2]))
    t2 = t1
    t3 = tuple(t1) # <==> t4 = t1[:]
    # t5 = copy.copy(t1)
    t6 = copy.deepcopy(t1)
    t1[1].append(100)

总结

  • 对于不可变对象

    • deepcopy与copy操作一样,都不为创建新对象,而是直接引用
    • 在后面如果有修改该不可变对象的操作时再创建新对象,此时两个版本的不可变对象地址变得不同
    • 这里是Python的常态,比如tuple(tuple1)将返回一个tuple1对象的引用而不是副本,当修改tuple1时才会创建新对象
    • 因为无论如何,修改不可变对象的不可变部分都不会修改原始对象,所以为了节约内存,Python解释器完全可以将创建新对象保留到修改内容时
  • 对于可变对象

    • deepcopy将创建新对象
    • copy只复制对象地址
    • 后面修改该可变对象时地址不变,而是直接修改内容

总之
deepcopy的目的就是确保,无论如何修改,原始对象和副本之间都完全独立
所以
只要是可能被修改的对象都要复制!!!
不可变对象在复制时会自动新建
故而deepcopy时不可变对象不用创建新对象

Python——Python中没有字符类型

Posted on 2018-10-02

不同于C++和Java等语言,Python中没有字符char类型,只有字符串类型


Python中的数据类型

标准数据类型

Numbers(数字)
String(字符串)
List(列表)
Tuple(元组)
Dictionary(字典)

关于字符类型的操作

  • 把长度为1的字符串当成字符来操作,比如函数ord(s)中只要s的长度为1(len(s) == 1)即可,否则ord函数抛出异常
    • 长度为1的字符串本质上还是一个字符串类型<type str>
  • 判断字符串某一位置的字符时直接比较即可,如
    1
    2
    3
    4
    5
    6
    7
    s = "12345"
    if s[2] == '2':
    print s[3]
    # 等价于
    if s[2] == "2":
    print s[3]
    # "2"和'2'都是<type str>类型的

Python——判断未知源的编码类型

Posted on 2018-09-30

有时候遇到一个文件,而我们并不知道它是什么编码方式编码的,本文给出了一些判断未知文件编码方式的方法


使用chardet包


在程序中判断

  • 安装Chardet包

    1
    pip install chardet
  • 使用Chardet包做判断

    1
    2
    3
    4
    5
    6
    import urllib
    rawdata = urllib.urlopen('http://yahoo.co.jp/').read()
    import chardet
    print chardet.detect(rawdata)
    # Output:
    {'confidence': 0.99, 'language': '', 'encoding': 'utf-8'}

更多高级使用方法可参考chardet文档


直接使用命令判断

  • 安装chardetect工具

    1
    pip install chardet
  • 使用chardetect命令

    1
    2
    3
    4
    # 检测test.txt文件的编码方式
    chardetect test.txt
    # Output:
    test-chardetect.txt: ascii with confidence 1.0

Ubuntu——ElasticSearch安装与配置(logstash)

Posted on 2018-09-29

ElasticSearch的安装与基本配置


安装ElasticSearch

  • 下载ElasticSearch deb安装包
  • 安装ElasticSearch
    • Ubuntu中默认安装路径为/usr/share/elasticsearch/
  • 配置ES为一个服务
    1
    2
    sudo /bin/systemctl daemon-reload
    sudo /bin/systemctl enable elasticsearch.service

启动ElasticSearch

1
sudo systemctl start elasticsearch.service

启动相关问题

  • 设置远程访问:
    • 修改config/elasticsearch.yml中network.host : 0.0.0.0
  • 可能遇到的问题1:

[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

  • 解决方案:https://www.cnblogs.com/chenjiangbin/p/12060899.html
  • 可能遇到的问题2:

[1]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]

  • 解决方案:https://blog.csdn.net/python36/article/details/84257343
  • 可能遇到的问题3:

[1]: the default discovery settings are unsuitable for production use; at least one of [discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes] must be configured

  • 解决方案:https://www.cnblogs.com/hellxz/p/11057234.html

关闭ElasticSearch

1
sudo systemctl stop elasticsearch.service

ElasticSearch的使用

ES的使用可从官网上查看,点击下一步接着可看完整个流程
*操作ES接口时,建议使用postman *

查看索引

1
GET /_cat/indices?v

health status index uuid pri rep docs.count docs.deleted store.size pri.store.size

创建索引

1
2
# 创建一个名字为customer的Index
PUT /customer?pretty

添加数据

给Index添加Document数据

1
2
3
4
5
6
# 向customer Index中添加id为1的Document
# 内容为{"name": "John Doe"}
PUT /customer/_doc/1?pretty
{
"name": "John Doe"
}

如果是使用Postman,这里选择json类型即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"_index" : "customer",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}

查询数据

1
2
# 从customer中查询id为1的数据
GET /customer/_doc/1?pretty
1
2
3
4
5
6
7
8
{
"_index" : "customer",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"found" : true,
"_source" : { "name": "John Doe" }
}

删除索引

1
2
# 删除名为customer的索引
DELETE /customer?pretty

修改数据

1
2
3
4
5
6
7
# 向customer Index中添加id为1的Document
# 如果目标Document已经存在,则修改目标Document为指定的数据
# 内容为{"name": "John Doe"}
PUT /customer/_doc/1?pretty
{
"name": "Joe Doe"
}

使用logstash同步数据

6.2.4同步mysql数据到ES

安装logstash

  • 下载logstash 6.2.4
    • 为了方便配置管理,建议下载zip或者tar.gz版本
  • 解压到指定文件夹,建议在相关项目下创建ElasticSearch文件夹,并存储以下数据
    • logstash 解压文件夹logstash-6-2-4
    • 新建文件: logstash更新 mysql 数据库索引到 ES 时的配置文件,一般命名为mysql.config [后面会给出详细内容]
    • 下载jdbc库: mysql-connector-java.jar [用于连接数据库]
      • 这里下载Platform Independent的压缩包版本解压即可找到需要的jar包

配置文件及jdbc连接库

  • 新建一个名为mysql.config的文件,内容为

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    # logstash-6.2.2\bin\logstash.bat -f mysql.config
    # logstash-6.2.4/bin/logstash -f mysql.config
    input {
    jdbc {
    # mysql jdbc connection string to our backup databse
    jdbc_connection_string => "jdbc:mysql://127.0.0.1:3306/docker_manager?serverTimezone=UTC"
    # the user we wish to excute our statement as
    jdbc_user => "docker"
    jdbc_password => "123456"
    # the path to our downloaded jdbc driver
    jdbc_driver_library => "/home/jiahong/Workspace/IdeaProjects/DockerManagerSystem/elastic-search/mysql-connector-java-8.0.11.jar"
    # the name of the driver class for mysql
    jdbc_driver_class => "Java::com.mysql.jdbc.Driver"
    # jdbc_paging_enabled => "true"
    # jdbc_page_size => "50000"
    # statement_filepath => "jdbc.sql"
    schedule => "* * * * *"
    # type => "jdbc"
    statement => "SELECT * FROM docker_manager.DockerManager_docker WHERE id > :sql_last_value"
    use_column_value => true
    tracking_column => "id"
    }
    }

    output {
    elasticsearch {
    hosts => "127.0.0.1:9200"
    index => "docker"
    document_id => "%{id}"
    }
    }
    • 关于mysql.config,一般需要配置的地方为:
      • jdbc_connection_string: 注意docker_manager为数据库名,后面的时区参数有时也需要修改,关于时区的问题可我的博客
        Linux——Logstash时区问题
      • jdbc_driver_library: 这里需指定到对应的jdbc连接库
      • statement: 数据库查询语句
      • jdbc_user: 数据库用户名l
      • jdbc_password: MySQL用户名对应的密码
      • hosts: 输出到ES地址
      • index: ES服务器的Index(相当于MySQL中的数据库)

利用logstash同步mysql数据库数据到ES

  • 启动同步操作
    1
    2
    3
    4
    # 进入之前创建用于解压logstash源文件的目录下
    cd ElasticSearch
    # 启动同步
    ./logstash-6.2.4/bin/logstash -f mysql.config

一旦同步开始,如果不关闭进程,那么将一直自动同步,建议同步完成(当输出不再变化)后关闭进程

  • 查看ES中相应的Index是否已经被更新

MySQL——Ubuntu18.04安装及配置

Posted on 2018-09-29

解决Ubuntu18.04安装Ubuntu后普通用户没有权限登录问题


安装

1
2
3
4
5
6
7
8
# 安装mysql服务
sudo apt-get install mysql-server
# 安装客户端
sudo apt install mysql-client
# 安装依赖
sudo apt install libmysqlclient-dev
# 检查状态
sudo netstat -tap | grep mysql

远程链接设置

默认远程链接问题

Ubuntu18.04 安装mysql后,普通用户没有连接mysql数据库权限(local或者remote均没有权限)

  • mysql -u root或者直接用使用MySQL Workbench连接均失败,显示如下错误

    ERROR 1045: Access denied for user: ‘root@localhost’ (Using password: YES)

  • 使用sudo mysql -u root能正确连接

打开远程链接数据

(删除之前的root并重新创建账户)

  • 登录

    1
    sudo mysql -u root
  • 然后查看当前用户

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    select User,Host from mysql.user;
    # Output:
    +------------------+-----------+
    | User | Host |
    +------------------+-----------+
    | admin | localhost |
    | debian-sys-maint | localhost |
    | magento_user | localhost |
    | mysql.sys | localhost |
    | root | localhost |
  • 删除root账号

    1
    drop user 'root'@'localhost';
  • 创建新的root账号

    1
    create user 'root'@'%' identified by '123456';
  • 为新账号授权

    1
    2
    grant all privileges on *.* to 'root'@'%' with grant option;
    flush privileges;
  • 退出

    1
    exit;
  • 以普通用户身份登录

    1
    mysql -u root -p

Python——反编译(Disassemble)与字节码(Bytecode)

Posted on 2018-09-29

为了知道Python代码底层都做了哪些操作,我们常常需要反编译Python代码以获得Python的字节码
我们可以获得: classes, methods, functions, or code 的字节码


获取字节码的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 比较`[]`和`list()`两者的不同
from dis import dis

# test case 1
dis("[]")
# Output:
1 0 BUILD_LIST 0
2 RETURN_VALUE

# test case 2
dis("list()")
# Output:
1 0 LOAD_NAME 0 (list)
2 CALL_FUNCTION 0
4 RETURN_VALUE

**由上述输出可知,`list()` 比 `[]` 会多执行一行字节码`LODA_NAME`**
1…678…20
Joe Zhou

Joe Zhou

世界上只有一种真正的英雄主义,那就是在认清生活真相之后依然热爱生活。 ——罗曼·罗兰

195 posts
38 tags
GitHub E-Mail
© 2024 Joe Zhou
Powered by Hexo
|
Theme — NexT.Gemini v5.1.4