Random Walk 随机游走

Introduction

Random Walk
Random Walk with Restart
Fast Random Walk

What’s Random Walk ?

Quoting from 重启随机游走算法(RWR)

随机游走算法的基本思想是,从一个或一系列顶点开始遍历一张图。在任意一个顶点,遍历者将以概率1-a游走到这个顶点的邻居顶点,以概率a随机跳跃到图中的任何一个顶点,称a为跳转发生概率,每次游走后得出一个概率分布,该概率分布刻画了图中每一个顶点被访问到的概率。用这个概率分布作为下一次游走的输入并反复迭代这一过程。当满足一定前提条件时,这个概率分布会趋于收敛。收敛后,即可以得到一个平稳的概率分布。

What’s Random Walk with Restart(RWR) ?

Let’s have some brief about RWR at first.
Quoting from What is Random Walk with Restart (RWR)?, it says :

RWR is a algorithm originally proposed for image segmentation. It iteratively explores the global structure of the network to estimate the proximity (affinity score) between two nodes. Starting at a node, the walker faces two choices at each step: either moving to a randomly chosen neighbor, or jumping back to the starting node. This algorithm only contains one fixed parameter r called ‘the restarting probability’ (with 1 − r for the probability of moving to a neighbor). After iteratively reaching stability, the steady probability vector contains the affinity score of all nodes in the network to the starting node. This steady probability vector can be viewed as the ‘influential impact’ over the network imposed by the starting node.

In addition to a single starting node, RWR can be extended to a set of starting nodes. In this context, the resulting steady probability vector can also be considered as the ‘influential impact’ over the network, but collectively imposed by a set of starting nodes.

The steady probability vector for a set of starting nodes can be calculated according to the steady probability vector for single starting nodes. For this reason, it is useful to pre-compute affinity matrix for nodes in the graph with respect to each starting node as a seed (by looping over every node in the graph). The motivation behind this is that this pre-computed affinity matrix can be extensively reused for obtaining affinity scores between any combinations of nodes. For instance, such a strategy can dramatically relieve the computational burden involved in sampling a large number of random node combinations. Therefore, this pre-computation does permit some flexibility in the downstream use, in particular for statistical testing.

Some features can be extracted from this quoting.
At first , RWR was first proposed for image sementation. Automatic Multimedia Cross-modal Correlation Discovery. It was proposed to solve the problem about proximity of two node in graph. Second, only one parmeter r ( restarting probability) and two choices (1.jumping batch to the starting node 2. move to a randomly chosen neighbor). After iteratively reaching stablility, the steady probability vector contains affinity score of all nodes in the graph to the starting node. That means in intuition, the more far away node from the starting node ,the less influence it has to the starting node.

重启随机游走算法是在随机游走算法的基础的改进。从图中的某一个节点出发,每一步面临两个选择,随机选择相邻节点,或者返回开始节点。算法包含一个参数a为重启概率,1-a表示移动到相邻节点的概率,经过迭代到达平稳,平稳后得到的概率分布可被看作是受开始节点影响的分布。重启随机游走可以捕捉两个节点之间多方面的关系,捕捉图的整体结构信息。

Words

affinity n. 类似, 近似, 密切关系.
burden n. 负担, 包袱, 责任 vt. 使烦恼, 劳累.
flexibility n. 柔度, 灵活性.

LeetCode 1 – 5

1. Two Sum

Difficulty : Easy
Description:

Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

Solution :

class Solution:
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        placeHolder = dict() 
        for i, x in enumerate(nums):
            if target - x in placeHolder:
                return placeHolder[target - x], i
            else:
                    placeHolder[x] = i

        return false

常见结题思路是暴力遍历(Brute Force), 时间复杂度会是O(N2), 空间复杂度为O(1).
可以通过维护一个字典来记录遍历过的元素和其对应index. 当遍历到新的元素时, 可以将target和新元素的差值和字典中的记录进行比较, 如果存在对应记录, 说明该差值存在, 并且对应索引是字典中差值对应的值, 返回相应答案即可.

2. Add Two Numbers

Difficulty : Medium
Description :

You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

You may assume the two numbers do not contain any leading zero, except the number 0 itself.

Example:
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.

Solution :


3

4. Median of Two Sorted Arrays

Difficulty : Hard
Description :

There are two sorted arrays nums1 and nums2 of size m and n respectively.

Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

You may assume nums1 and nums2 cannot be both empty.

Example 1:
nums1 = [1, 3]
nums2 = [2]
The median is 2.0

Example 2:
nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5There are two sorted arrays nums1 and nums2 of size m and n respectively.

Solution:

class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        len1 = len(nums1)
        len2 = len(nums2)

        index_l = []

        total_len = len1 + len2
        if total_len % 2 == 0:
            index_l.append(total_len / 2 - 1)
            index_l.append(total_len / 2)
        else:
            index_l.append((total_len -1 ) / 2)

        result = 0
        index_1 = 0 
        index_2 = 0
        for i in range(total_len):
            current = 0
            if index_1 >= len1 and index_2 < len2:
                current = nums2[index_2]
                index_2 += 1
            elif index_2 >= len2 and index_1 < len1:
                current = nums1[index_1]
                index_1 +=1
            elif nums1[index_1] < nums2[index_2]:
                current = nums1[index_1]
                index_1 += 1
            else:
                current = nums2[index_2]
                index_2 += 1
            if index_l :
                if i in index_l:
                    result += current
                    index_l.remove(i)
            else :
                break

        if total_len % 2 == 1:
            return result
        else:
            return result / 2

5. Longest

Difficulty : Medium
Description :

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of s is 1000.

Example 1:
Input: “babad” Output: “bab”
Note: “aba” is also a valid answer.

Example 2:
Input: “cbbd” Output: “bb”

Solution
python3

第一章 概率论的基本概念

P1 – 24 正文
P24 – 29 习题
确定性现象 : 在一定条件下必定发生的一类现象, 称为确定性现象.
随机现象: 在个别试验中结果呈现不确定性, 但在大量重复试验中其结果又具有统计规律性的现象,称为随机现象.
统计规律性: 在大量重复试验或观察中所呈现除的固有规律性称为统计规律性.

1 随机试验

随机试验的特点:
1. 可以在相同的条件下重复地进行;
2. 每次试验的可能结果不止一个, 并且能实现明确试验的所有可能结果.
3. 进行一次试验之前不能确定哪一个结果会出现.

满足上述三个特点的试验被称之为随机试验.

2. 样本空间, 随机事件

2.1 样本空间

样本空间 : 随机试验E的所有可能结果组成的集合称为E的样本空间, 记为S.
样本点 : 样本空间的元素, 即E中的每个结果, 称为样本点.

2.2 随机事件

随机事件 : 试验E的样本空间S的子集为E的随机事件, 简称事件.
在每次试验中, 当且仅当该子集中的一个样本点出现时, 称 该事件发生.
基本事件 : 由一个样本点组成的单点集, 称为基本事件.
必然事件 :样本空间S包含所有的样本点, 它是S自身的子集, 在每次试验中它总是发生, 因此S称为必然事件.
不可能事件: 空集\\emptyset不包含任何样本点, 它也作为样本空间的子集, 在每次试验中都不发生, \\emptyset称为不可能事件.

2.3 事件间的关系与事件的运算

事件相等
和事件
积事件
差事件
互斥事件
逆事件 / 对立事件

事件定律:
交换律(commucative law)
结合律(associative law)
分配律(distribution law)
德摩根律(De Morgan law)

3. 频率与概率

3.1 频率

频数
频率
频率的性质

3.2 概率

4. 等可能概型(古典概型)

等可能概型定义

超几何概率的分布公式

实际推断原理 : 概率很小的事件在一次试验中实际上几乎是不发生的.

5. 条件概率

5.1 条件概率

事件A已发生的条件下事件B发生的概率

5.2 乘法定理

5.3 全概率公式和贝叶斯公式

样本空间S的划分
全概率公式
贝叶斯公式

先验概率
后验概率

6. 独立性

事件相互独立
两事件相互独立 + 三事件相互独立

Q&A

Q1. 在一批灯泡中任意抽取一只, 测试它的寿命. 该试验可以被看做随机试验么?
A1. 可以. 该试验的样本空间为 S:{t | t>= 0 } 也就是说, 随机试验的样本空间未必是可以一一穷举的.

Head First Statistics

1. 信息图形化

概念整理:
统计
信息和数据的区别?
饼图 + 条形图/水平条形图/堆积条形图/分段条形图 + 直方图

标度 : 百分数标度 + 频数标度

要点:
频数是一种统计方法, 用于描述一个类别中有多少个项.

集中趋势的量度

均值和平均数的区别
均值的两个表达式(全统计和频数统计) 和 符号 μ

异常值 : 和其他数据格格不入的极高或极低的数值.
偏斜数据 :

  1. 均值和中位数的区别?
    在数据存在偏斜的情况下, 中位数更能很好的表现数据分布.
    大多数情况系, 均值远优于中位数, 尤其对抽样数据来说.

P62

怎么判断数据倾斜发现?
尾巴往哪儿甩 就是哪倾斜, 而不是数据头部在哪里倾斜在哪里.

众数也是平均数的一种

如果有两个众数, 则是双峰数据.

众数组: 具有最高频数的组.

众数在众数较多时最没用.

众数必须存在数据集中.
众数是唯一能用于类别数据的平均数.

P78值得记录.

P83 第三章

全距: 数据的扩展范围. 也叫极差.
用数据集中最大值减去最小值, 最大值叫上界, 最小值叫下界.

全距仅描述了数据的范围, 并没有描述数据在上,下界之间的分布形态.

全距很容易受异常值的影响.

四分位数: 将整个数据一分为四的几个数值.

上四分位数, 下四分位数, 中位数,

四分位距 = 上四分位数 – 下四分位数

四分位距和全距相比, 较少受到异常值的影响.

Chapter 4. 概率

样本空间

维恩图
对立事件

互斥事件 : 如果两个事件是互斥事件, 则只有其中一个事件会发生. ( 如果两个事件中只有一个会发生, 能不能说这两个事件是互斥事件?)
相交事件 : 如果两个事件相交, 则这两个事件有可能同时发生.

如果P149, 则说A和B穷举.

条件概率

概率树

全概率公式

贝叶斯定理

Chapter 5. 离散概率分布的运用

\$\sigma\$

WishList

  1. CS231N 2017 李飞飞视觉课程
  2. GAN实现
  3. Transformer实现
  4. Encoder-Decoder 实现
  5. Attention机制了解
  6. TransE 等系列实现
  7. PRA 等系列实现
  8. 遗传,退火算法实现
  9. 线性代数复习 + 习题册练习
  10. 统计复习 + 习题册联系
  11. 传统机器学习相关知识整理
    12. Coursera上的deeplearning.ai课程 在网易云课堂上有 可以先上这个 然后去Coursera上拿个证书. 不过这个需要尽快 节省费用.
  12. 和阿木组队参加的DC比赛, 目标Top10
  13. CSDN 皮果提的博客写的很好 可以浏览一遍
  14. 选择一个数据集, 尝试使用各种模型比较一遍 CIF10.
  15. 整理下各个数据集 FashionMNIST.
  16. 复习老算法 例如红黑树 B+树等 图的遍历等 树的遍历等
  17. 强化学习实践
    19. 对话管理

Viterbi
Gibbs Sampling
RNN
CNN
CRF
Trie

浙大 概率论与数理统计 四-八章学习 习题

nan is not nan?

nan is not nan ?

遇到一个判断值是否为nan的问题.
用pandas读取csv文件, 其中一些列值为nan.
正常的读取之后, 将row结合col转换成dict进行存储, 这样有一些空值的列就会转换成numpy.nan.

param_dict = {'col1':1, 'col2':nan,'col3':3}

如果用{k,v for k,v in param_dict.items() if v is not nan}进行判断, 就会出现诡异的现象. 有些nan值并不能被排除.
必须调用numpy.isnan(v) 进行判断.

具体的后续再分析, 这里做个记录.

Why always ‘ImportError: No module named ***’ ?

为什么在IDE中可以正常run起来的项目, 从命令行中启动就会报Import Error?

Python中,每个py文件被称之为模块(module),每个具有init.py文件的目录被称为包(package)。只要模块或者包所在的目录在Python的sys.path中,就可以使用import 模块或import 包来使用.
如果你要使用的模块(py文件)和当前模块在同一目录,只要import相应的文件名就好,比如在a.py中使用b.py:

import b

但是如果要import一个不同目录的文件(例如b.py)该怎么做呢? 首先需要使用sys.path.append方法将b.py所在目录加入到搜素目录中。然后进行import即可,例如

import sys
sys.path.append('c:\xxxx\b.py')`# 这个例子针对 windows 用户来说的 

大多数情况,上面的代码工作的很好。但是如果你没有发现上面代码有什么问题的话,可要注意了,上面的代码有时会找不到模块或者包(ImportError: No module named xxxxxx),这是因为sys模块是使用c语言编写的,因此字符串支持 ‘\n’, ‘\r’, ‘\t’等来表示特殊字符。所以上面代码最好写成:

sys.path.append('c:\\xxx\\b.py') 
或者sys.path.append('c:/xxxx/b.py') 

这样可以避免因为错误的组成转义字符,而造成无效的搜索目录(sys.path)设置。

sys.path是Python的搜索模块的路径集,是一个list, 可以在Python 环境下使用sys.path.append(path)添加相关的路径,但在退出Python环境后, 自己添加的路径就会自动消失了!

原因在于从IDE启动的项目或者模块, 会在运行时将当前工程的所有文件夹路径都作为包的搜索路径, 其本身已经将对应路径加入刀sys.path中了. Python在启动时, 会自动从sys.path中寻找路径来寻找对应的模块, 如果找不到,则会跑出ImportError.
所以, 从命令行中启动时, sys.path只包含Python自带的一些路径, 而没有加入自定义的模块/包的路径, 所以会导致

IDE :
['/home/bp/PycharmProjects/untitled1/dir2', '/home/bp/PycharmProjects/untitled1/dir2', '/home/bp/PycharmProjects/untitled1', '/home/bp/PycharmProjects/untitled1/dir1', '/home/bp/VirtualEnvs/tensorflow0625/lib/Python35.zip', '/home/bp/VirtualEnvs/tensorflow0625/lib/Python3.5', '/home/bp/VirtualEnvs/tensorflow0625/lib/Python3.5/plat-x86_64-linux-gnu', '/home/bp/VirtualEnvs/tensorflow0625/lib/Python3.5/lib-dynload', '/usr/lib/Python3.5', '/usr/lib/Python3.5/plat-x86_64-linux-gnu', '/home/bp/VirtualEnvs/tensorflow0625/lib/Python3.5/site-packages', '/usr/local/lib/Python3.5/dist-packages', '/usr/lib/Python3/dist-packages']

Terminal :
['', '/usr/lib/Python35.zip', '/usr/lib/Python3.5', '/usr/lib/Python3.5/plat-x86_64-linux-gnu', '/usr/lib/Python3.5/lib-dynload', '/usr/local/lib/Python3.5/dist-packages', '/usr/lib/Python3/dist-packages']

Solutions

常见的方式有三种
1. import
如果引用的文件和当前文件在一个文件夹下, 可以直接import

  1. sys.append

  2. *.pth
    在site-package下添加.pth文件, 在文件内用 绝对路径 标明引用路径.

将自己做的py文件放到 site_packages 目录下:

下面命令显示了 site-packages 目录:

python -c “from distutils.sysconfig import get_python_lib; print get_python_lib()”

但是这样做会导致一个问题,即各类模块都放到此文件夹的话,会导致乱的问题,这一点是显而易见的。

注意,也不创建子文件夹,再将自己的模块放到子文件夹解决问题,这会导致使用import 语句时错误。

使用pth文件,在 site-packages 文件中创建 .pth文件,将模块的路径写进去,一行一个路径,以下是一个示例,pth文件也可以使用注释:

# .pth file for the  my project(这行是注释)
E:\DjangoWord
E:\DjangoWord\mysite
E:\DjangoWord\mysite\polls

这个不失为一个好的方法,但存在管理上的问题,而且不能在不同的python版本中共享。

Boob!

上述的部分解释了引发ImportError的缘由, 这里给出一个可以通过递归添加项目目录下所有包路径的方法.

def append_sys_path(root_path=None):
    """
    递归添加项目下所有的Package路径.
    :return:
    """
    if root_path is None:
        pro_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
    else:
        pro_dir = root_path

    result_dir = [pro_dir]
    while result_dir:
        single_dir = result_dir.pop()
        init_flag = False
        subdir_list = []
        for single_path in os.listdir(single_dir):
            if single_path == '__init__.py':
                init_flag = True  # 根据当前目录是否存在__init__.py文件判断是否为package.
            single_path = os.path.join(single_dir, single_path)
            if os.path.isdir(single_path):
                subdir_list.append(single_path)
        if init_flag:
            sys.path.append(single_dir)
        result_dir.extend(subdir_list)

其他介绍ImportError的文章

  1. Python 101: All about imports
  2. Python导入模块的几种姿势 – 链接1的中文译文

Parallel Programming in Python

Parallel in Python

并行计算在Python中并不少见, 相关多线程,多进程,threading, Pool, Queue的介绍网上都有很多资料, 这里不做赘述. 下面主要从几个常见的问题出发, 了解一些概念之间的问题(Based on Python3).

哪个是我该用的Queue?

Queue是个在多进程中是个让人困惑的概念. 可以用多个方式导入Queue, 分别是 multiprocessing.queues.Queue, 和 multiprocessing中Manager中的Queue, 还有queue中的Queue

从Manager中导入的Queue

from multiprocessing import Manager
m = Manager()
q_from_manager = m.Queue()

Manager默认是multiprocessing中SyncManager类, SyncManager类中的Queue()方法则返回queue.Queue(). 但是并不是说由Manager生成的Queue 和 queue.Queue是一样的. 相反, 在Pool,Process和父进程通信的过程中, Manager.Queue可以很好的实现父子进程间通信, 子进程间通信, 而queue.Queue()并不能, 说明Manager通过继承的multiprocessing.managers.BaseManager中的机制来保障进程间通信, 而queue.Queue()只是实现这一机制的底层.

通过multiprecessing导入Queue

from multiprocessing import Queue
q = Queue(1)
print(type(q))
<class 'multiprocessing.queues.Queue'>

说明 from multiprocessing import Queue 导入的 Queue本质是 multiprocessing.queues.Queue, 但是后者的init方法为 __init__(self, maxsize=0, *, ctx), 需要更多的配置, 所以在使用上还需配置, 不推荐使用.

这样就可以把正常使用的Queue缩小到两个范围 from multiprocessing import Queue 和 Manager的Queue()方法. 下文简写为 mp.Queue 和 mgr.Queue

mp.Queue 可以用于spawn出的子进程间通信, 也可以用于 父进程和 spawn出的子进程通信,
multiprocessing.Queue只能用于显示地用Process创建的子进程间或与子进程与父进程之间通信;
multiprocessing.Manager.Queue 能用于Pool创建的子进程之间通信, 也能用于父进程和子进程通信, 也能用于Process进程与Pool创建的子进程之间通信. 这个还是比较强大的功能.
这段以后再写. 需要重新设计一遍对应的实验.

选择合适的Queue

from queue import Queue
普通的队列模式

from multiprocessing import Queue
多进程并发的Queue队列, 用于解决多进程间通信问题.

如果要用进程池, 则必须使用Manager.Queue()

问题

仍留下的问题是, 如果用Pool, 还需不需要用JoinableQueue, 或者, 该怎么结束Pool中的进程? #TODO 仍需要找一个案例, 能够很好的解释如何停止Pool中的进程.

Terminate multi process/thread in Python correctly and gracefully中有很好的如何解决Process结束的问题. 但仍有一些点需要注意.
例如, 在Problem1中提到的结束无限循环子进程的解决方案中, 使用了Process.terminate方法. 这个案例其实主要表现的是, 在子进程的join之前的所有父进程代码均会执行, 然后阻塞在join语句. 这样, 因为子进程是无限循环, 所以不会自己结束, 从而有必要在父进程中显示的调用子进程的terminate语句. 但是调用terminate的时候如果子进程的任务没有完成, 也会被立刻消灭. 这就会导致很难看的结果.

import multiprocessing
import time

def hang():
    while True:
        print('hanging..')
        time.sleep(10)
        print('after 10 , hanging...')

def main():
    p = multiprocessing.Process(target=hang)
    p.start()
    time.sleep(1)
    p.terminate()
    p.join()
    print('main process exiting..')

if __name__ == '__main__':
    main()

子进程会在父进程休眠1秒之后执行剩下的语句, 也就是terminate, 这时子进程仍处在sleep(10)中, 所以这时候被结束, 会导致第二个print语句不被执行.

在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,10几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,这时候进程池Pool发挥作用的时候就到了。
Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。这里有一个简单的例子

#!/usr/bin/env python
#coding=utf-8
from multiprocessing import Pool
from time import sleep

def f(x):
    for i in range(10):
        print '%s --- %s ' % (i, x)
        sleep(1)


def main():
    pool = Pool(processes=3)    # set the processes max number 3
    for i in range(11,20):
        result = pool.apply_async(f, (i,))
    pool.close()
    pool.join()
    if result.successful():
        print 'successful'


if __name__ == "__main__":
    main()

先创建容量为3的进程池,然后将f(i)依次传递给它,运行脚本后利用ps aux | grep pool.py查看进程情况,会发现最多只会有三个进程执行。pool.apply_async()用来向进程池提交目标请求,pool.join()是用来等待进程池中的worker进程执行完毕,防止主进程在worker进程结束前结束。但pool.join()必须使用在pool.close()或者pool.terminate()之后。
其中close()跟terminate()的区别在于close()会等待池中的worker进程执行结束再关闭pool,而terminate()则是直接关闭。result.successful()表示整个调用执行的状态,如果还有worker没有执行完,则会抛出AssertionError异常。
利用multiprocessing下的Pool可以很方便的同时自动处理几百或者上千个并行操作,脚本的复杂性也大大降低。

没有找到合适的方法能够让Pool中的进程自动的停止. 如果没有正规的方式的话, 估计是要用ternimate语句在父进程中显示的调用, 从而停止Pool中的子进程.

如何在thread, multiprocessing subprocess中选择合适任务的并行实现方式?

经常遇到的一个问题是, 不知道该怎样选择一个合适任务的并行实现方式. 在Stack Overflow上有个很好的解答 Deciding among subprocess, multiprocessing, and thread in Python?
从这个回答中不难看出, subprocess 往往用来提供同步反馈. 可以在主进程中spawn出一个subprocess, 在子进程中完成一些任务, 然后等待子进程的完成或读取子进程的输出. 理论上来说可以spawn出100甚至更多的subprocess来完成任务, 但是最大的缺点在于subprocess的I/O block.

multiprocessing往往是python用来实现真正并行的方式. 引用回答中的话,

multiprocessing is for running functions within your existing (Python) code with support for more flexible communications among this family of processes.

而且multiprocessing还可以规避GIL的问题, 从而方便的扩展到CPU的多核上实现并行.

而threading则是一个受用面很窄的用法, 因为它天然I/O限制, 无法扩展到多核CPU上.

综上而言, 如果只是想单独的把一个任务放在主进程之外进行, 可以用subprocess; 如果是想高效并行的话, 用multiprocessing ; 少用threading(个人意见). 想知道更多的区别, 可以去答案里看.

Process类继承

from multiprocessing import Queue, Process, current_process
import os
from time import sleep
from random import randint


class Producer(Process):
    def __init__(self, queue): # Override
        Process.__init__(self) # 加入父类init
        self.queue = queue 

    def run(self): # 调用start()时会调用run(run为单进程).
        while True:
            self.queue.put('one product')
            print(current_process().name + str(
                os.getpid()) + ' produced one product, the no of queue now is: %d' % self.queue.qsize())
            sleep(randint(1, 3))


class Consumer(Process):
    def __init__(self, queue):
        Process.__init__(self)
        self.queue = queue

    def run(self):
        while True:
            d = self.queue.get(1)
            if d != None:
                print(current_process().name + str(os.getpid()) + ' consumed  %s, the no of queue now is: %d' % (
                    d, self.queue.qsize()))
                sleep(randint(1, 4))
                continue
            else:
                break


if __name__ == "__main__":
    queue = Queue(40)
    # Init
    processed = []
    for i in range(3):
        processed.append(Producer(queue))
    processed.append(Consumer(queue))

    # Start
    for i in range(len(processed)):
        processed[i].start()

    # Join
    for i in range(len(processed)):
        processed[i].join()

Useful Links

An introduction to parallel programming using Python’s multiprocessing module
Python Multiprocessing: Pool vs Process – Comparative Analysis
孤儿进程与僵尸进程

Mac OS系统下Python多进程Debug卡死状态

介绍
TEMP.py用于启动多进程读取文件,并行处理并写入文件中.

首先利用ps aux | grep TEMP.py查找对应pid.

(virtualenv_3.6.5) localhost:other_requriment root$ ps aux | grep TEMP.py
root             10859   0.0  0.0  4286184    972 s000  S+    8:07PM   0:00.01 grep TEMP.py
root             10797   0.0  0.0  7846872   1300   ??  S     7:50PM   0:16.63 bin/python3.6 /TEMP.py
root             10796   0.0  0.1  7875000   4360   ??  S     7:50PM   0:30.04 bin/python3.6 /TEMP.py
root             10795   0.0  0.1  7875000   4256   ??  S     7:50PM   0:30.23 bin/python3.6 /TEMP.py
root             10794   0.0  0.1  7875256   4236   ??  S     7:50PM   0:29.77 bin/python3.6 /TEMP.py
root             10793   0.0  0.1  7875256   4236   ??  S     7:50PM   0:29.26 bin/python3.6 /TEMP.py
root             10792   0.0  0.0  7847908   1824   ??  S     7:50PM   0:00.10 bin/python3.6 /TEMP.py
root             10791   0.0  0.0  7853028   1336   ??  S     7:50PM   0:08.25 bin/python3.6 /TEMP.py
root             10782   0.0  0.3  7846080  24124   ??  S     7:50PM   0:01.77 bin/python3.6 /TEMP.py

(virtualenv_3.6.5) localhost:$ pstree 10782
-+- 10782 root bin/python3.6 PROJECT/TEMP.py
 |--- 10791 root bin/python3.6 PROJECT/TEMP.py
 |--- 10792 root bin/python3.6 PROJECT/TEMP.py
 |--- 10793 root bin/python3.6 PROJECT/TEMP.py
 |--- 10794 root bin/python3.6 PROJECT/TEMP.py
 |--- 10795 root bin/python3.6 PROJECT/TEMP.py
 |--- 10796 root bin/python3.6 PROJECT/TEMP.py
 \--- 10797 root bin/python3.6 PROJECT/TEMP.py

使用dtruss进行进程情况查看(类似Linux系统中的strace).

(virtualenv_3.6.5) localhost:$ sudo dtruss -p 10782
dtrace: system integrity protection is on, some features will not be available

SYSCALL(args)            = return
gettimeofday(0x7000046A9C68, 0x0, 0x0)           = 0 0
gettimeofday(0x7000047AC538, 0x0, 0x0)           = 0 0
psynch_cvwait(0x7FE75A178168, 0x100000100, 0x0)          = -1 Err#316
gettimeofday(0x7000046A9C68, 0x0, 0x0)           = 0 0
psynch_cvwait(0x7FE75A178168, 0x100000100, 0x0)          = -1 Err#316

查询子进程10791 – 10797
发现除了10792报错和主进程一样之外, 其他子进程均和10793一样, 没有报错.

(virtualenv_3.6.5) localhost:other_requriment didi$ sudo dtruss -p 10792
dtrace: system integrity protection is on, some features will not be available

SYSCALL(args)            = return
gettimeofday(0x7FFEE9E28BA8, 0x0, 0x0)           = 0 0
psynch_cvwait(0x7FE75A236A88, 0x100000100, 0x0)          = -1 Err#316

(virtualenv_3.6.5) localhost:other_requriment didi$ sudo dtruss -p 10793
dtrace: system integrity protection is on, some features will not be available

SYSCALL(args)            = return

Linux系统下可以进入/proc/$PID/ 下 cat status 或者进入fd进行查看, 但是Mac OS系统下没有/proc目录, 所以根据Mac OS X equivalent of VirtualQuery or /proc/pid/maps?的推荐, 使用**vmmap**进行查看(需要root权限). 命令输出的信息较多(看不太懂这里的内容输出).

Stack Overflow上有类似的问题
Interpret dtruss output like “psynch_cvwait(…) = -1 Err#316”
问题中的回答提到

/*
 *  psynch_cvwait: This system call is used for psynch cvar waiters to block in kernel.
 */
int
psynch_cvwait(__unused proc_t p,
              struct psynch_cvwait_args * uap,
              uint32_t * retval)

也就是说, psynch_cswait是用来允许psynch cvar waiters在内核中block的.

Linux上调试类似问题
调试卡死的Python进程
用strace查找进程卡死原因