0%

在项目中,常常会需要处理一个list数据列表,使用多线程来加速数据的处理。

需要保证两点:

  1. 能灵活控制线程的数量
  2. 能够同步的完成一批list的数据

可以使用信号量和线程池,具体实现代码如下:

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
32
33
public static <T> void startWithMultiThread(List<T> list, int nThread, Consumer<T> func) {
if (CollectionUtils.isEmpty(list)) {
return;
}
if (nThread <= 0) {
return;
}
if (func == null) {
return;
}
if (CollectionUtils.isEmpty(list)) {
return;
}
Semaphore semaphore = new Semaphore(nThread);//定义几个许可
ExecutorService executorService = Executors.newFixedThreadPool(nThread);//创建一个固定的线程池
for (T obj : list) {
try {
semaphore.acquire();
executorService.execute(() -> {
try {
func.accept(obj);
semaphore.release();
} catch (Exception ex) {

}
});
} catch (InterruptedException e) {

}
}
executorService.shutdown();
}

阅读全文 »

线程和进程

对于进程和线程的概念可以简单的理解成一个包含关系,例如:一个人个体可以称为社会的一个进程,人可以同时做很多事情,这个称之为线程

CPU一次只能执行一个指令,操作系统为了保证同一时刻多个程序同时执行, 把每次执行的指令过程分成若干时间片(timeslice),每一个程序都会在指定的时间片上运行一段时间后,然后保存运行的上下文资源,来保证下次执行。

由于进程对于资源的需求比较多,保存和恢复都会需要很多时间,CPU每次执行的单位都是线程

所以单核的CPU的执行其实本质都是单线程.

例如我们同时运行A、B、C三个程序:

程序执行

疑问:如果是多线程本质还是单线程执行为什么我们还要使用多线程?

因为在程序执行的过程的中,CPU的执行速度大于内存,也远远大于磁盘IO的运算,如果一个程序CPU执行完成后,要等待磁盘和内存的读取。在等待期间,CPU处于空闲的状态,这样就导致的资源的浪费。

多线程的引入是在CPU存在空闲的时间片的时候,能够有指令被执行,不必再等待其他的执行。

阅读全文 »

枚举

python中,枚举使用Enum模块。 具体使用如下:

1
2
3
4
5

from enum import Enum

Week=Enum("Week",('Mon','Tue','Wen','Thu','Fri','Sta','Sun'))

在枚举中可以自动为下面的变量赋值,我们可以使用迭代把数据显示出来:

1
2
3
4
5
from enum import Enum
Week=Enum("Week",('Mon','Tue','Wen','Thu','Fri','Sta','Sun'))

for k, v in Week.__members__.items():
print(k, ':', v, ',', v.value)

打印结果:

1
2
3
4
5
6
7
Mon : Week.Mon , 1
Tue : Week.Tue , 2
Wen : Week.Wen , 3
Thu : Week.Thu , 4
Fri : Week.Fri , 5
Sta : Week.Sta , 6
Sun : Week.Sun , 7

如果像自定义枚举的值,可以使用继承的方法,自定义一个枚举:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from enum import Enum, unique

class Week(Enum):
Sun = 0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6

for k, v in Week.__members__.items():
print(k, ':', v, ',', v.value)

打印结果:

阅读全文 »

模块


随着项目增大,功能越来越复杂,为了提高代码的复用性和降低功能间的耦合,提出了模块的概念。

python中有很多的模块,使用时候直接用import导入对应的包就可以使用。

1
import sys

这样就导入了一个sys模块,我们可以在代码中直接使用:

1
2
3
4
5
import sys
def func():
print (sys.argv)

func()

打印结果是当前的文件所在的路径。

解释sys的作用:
sys.argv 用list来存储命令行传过来的参数。第一个参数是.py文件名称,例如:

python3 xxx.py 运行结果就是['xxxx.py']

阅读全文 »

python的函数也属于一个对象,可以有一个变量来代替,例如前面说过的一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
f=abs
print(f(-10))
```

如果我们在不改变原来函数的前提下,想扩展一个函数的功能。可以重新定义一个函数,把要原函数作为参数传递给`增强函数`,在调用函数前执行一些动作。

```python
def revert(a):
return abs(a)

def new_func(func):
print("do something")
return func

f=new_func(revert)
print(f(-10))

打印结果是:

1
2
do something
10

对于上面的代码,new_func就是装饰器,可以使用@对其进行简化:

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
32
33
def new_func(func):
print("do something")
return func

@new_func
def revert(a):
return abs(a)

print(revert(-10))

```

这样可以省去一个变量的定义,也维持了原来的方法名称。


上面的装饰器有点过于简单,因为我们只能在`return` 语句前增加内容,想在方法后面增加一个确不行,为了能够实现更强大的装饰器,我们可以对其做修改,再增加一层函数:

``` python
def new_func(func):
def inner(a):
print("do something")
res=func(a)
print("something is done")
return res
return inner

@new_func
def revert(a):
print ("processing")
return abs(a)

print(revert(-10))

打印结果:

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
do something
processing
something is done
10
```

上面这个装饰器基本满足了我们的需求,但同样还有一个问题,上面的装饰器,只能传递一个参数,所以还是不够一般性。

我们可以使用函数的默认值的方法来解决这个问题,官方给的是`*args 和 **kwargs`(tuple和dict类型),修改如下:

``` python
def new_func(func):
def inner(*args,**kw):
print("do something")
res=func(*args,**kw)
print("something is done")
return res
return inner
@new_func
def revert(a):
print ("processing")
return abs(a)

print(revert(-10))

我们再增加一个方法:

1
2
3
4
5
6
@new_func
def add(x,y):
print ("processing")
return x+y;
print(add(1,2))

阅读全文 »

函数式编程 主要思想是把运算过程尽量写成一系列嵌套的函数调用,不严谨的说:可以把函数的引用传递给变量。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> abs(-10)
10
>>> f=abs
>>> f(-10)
10
```
`f`就引用了abs函数的地址。

1. 可以把函数当成参数传递给另一个函数:

```python
def add(x,y,f):
return f(x)+f(y)
print(add(-1,2,abs))
  1. 函数也可以当成返回值:

    1
    2
    3
    def getMethod():
    return abs
    print(getMethod()(-1))

    打印结果是:1

  2. python也支持lambda表达式

    1
    2
    f=lambda x:x+x
    print(f(10))

    打印结果是:10

  3. 可以固定一个函数的默认值,返回一个新函数

    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
         import functools
    def add(x="2"):
    print(x)
    add()
    add1=functools.partial(add, x="5")
    add1()
    ```
    打印结果:`2 5`

    我们使用`functools.partial`方法把`add`的默认值修改成一个新的函数`add1`


    #### 常用的几个函数

    - map和reduce使用

    `map`函数的格式可以大致的表示为:`map(func,[])`,其功能就是把数组的每一个元素代入到`func`函数中,具体的实现功能如下:

    `list(map(abs,[-1,3,4,-6]))`,打印结果是:[1,3,4,5]

    我们可以根据其定义编写对应的功能:

    ```python
    def map1(func,arr):
    l=[]
    for x in arr:
    yield func(x)

    print(map1(abs,[1,-3,-4,6]))
    ```

    `reduce`是一个累计的函数,把上次计算的结果,当成下次运行的一个参数:`s1=f(x,y);s2=f(s1,z);`

    ``` python
    def add(x,y):
    return x+y
    print(reduce(add,[1,-3,-4,6]))
    ```
    计算结果:`1-3-4+6=0`

    用python代码来表示`reduce`

    ``` python
    def reduce1(func,arr):
    s=0
    for x in arr:
    s=func(s,x)
    return s;

阅读全文 »

函数的定义


python使用def来定义

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
def print_str(x):
print (x)
```
调用`print_str("12")` 打印`12`


#### 默认参数
----------------------------

`python`支持默认参数。

```python
def print_str(x,y="end"):
print (x,y)
```

调用`print_str("12")`,不传递y参数 打印`12 end`
调用`print_str("12","continue")` 打印`12 continue`

如果是多个默认参数,可以根据参数的名称来指定参数。

``` python
def print_str(x,y="y",z="z"):
print ("x:",x)
print ("y:",y)
print ("z:",z)

当调用print_str(1,2),打印结果:

1
2
3
4
5
6
7
8
9
10
x: 1
y: 2
z: z
```

当调用`print_str(1,z=2)`,打印结果:
``` cte
x: 1
y: y
z: 2

使用默认参数需要注意一个问题:默认定义的时候,默认参数值已近计算出来,如果是一个默认参数是一个引用,则会发生改变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def add_dict(arr=[]):
arr.append("end")
print (arr)
add_dict()
add_dict()
add_dict()
```

打印结果如下:

```cte
['none']
['none', 'none']
['none', 'none', 'none']

所以,如果使用可变的引用变量,则注意这种形式。可以使用None来代替:

1
2
3
4
5
6
def add_dict(arr=None):
if arr is None:
arr=[]

arr.append("end")
print (arr)

可变参数

阅读全文 »

数组的切片

定义一个数组

1
arr=list(range(100))
  1. 数组取前3个元素 arr[0:3],0可以省略,arr[:3],打印结果:[0,1,2]

  2. 数组取后面三个元素: arr[-3:0],也可写为:arr[-3:],打印结果:[97,98,99]

  3. 数组取后面三个元素: arr[97:],是跳过前97个数字,打印结果:[97,98,99]
  4. 可以指定取值的间隔 arr[:10:2],打印结果:[0, 2, 4, 6, 8]
    如果在全部范围内查询,可以省略查询的个数,arr[::2]这样打印出来所有的偶数。

  5. 切片的方法同样适用于tuple

  6. 字符串可以看成是字符的数组,可以使用,"ABCDEFG"[:3] 输出结果ABC

迭代循环

  1. list的循环

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
         arr=list(range(10))
    for a in arr:
    print(a)
    ```

    2. `dict`循环

    ```python
    dict={"a":1,"b":2,"c":3}
    for a in dict:
    print(a)
    ```

    ```python
    dict={"a":1,"b":2,"c":3}
    for x,y in dict.items():
    print(x,y)
    ```

    ``` cte
    a 1
    b 2
    c 3

  2. 字符串循环

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
         for a in "ABCD": 
    print(a)

    ```
    4. 多个变量
    ```python
    for x, y in [(1, 1), (2, 4), (3, 9)]:
    print(x, y)

    ```
    打印结果:
    ``` cte
    1 1
    2 4
    3 9
  3. 带索引的循环写法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    for i, value in enumerate(['A', 'B', 'C']):
    print(i, value)

    ```
    打印结果:

    ```cte
    0 A
    1 B
    2 C
  4. 判断能否被迭代

    1
    2
    3
    from collections import Iterable
    isinstance('abc', Iterable)

列表生成式

列表生成式可以更简单的把生成一个list或者tuple.

定义一个100的数组,arr=list(range(100))

  1. 定义一个100偶数的数组

    1
    2
    3
    4
    arr=[2 * x for x in list(range(100))]

    或者arr=[x for x in list(range(200)) if x%2==0]

    打印结果:[0,2,4...198]

  2. 定义两个循环生成一个组合

    1
    str=[a+b for a in "ABC"  for b in "XYZ"]  

    打印结果:['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

  3. 使用多个变量

    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
    32
    33
    34
    35
         dict = {'a': 'A', 'b': 'B', 'c': 'C' }
    dic=[k + '=' + v for k, v in dict.items()]
    print(dic)
    ```

    打印结果:`['a=A', 'b=B', 'c=C']`

    4. 使用函数

    ``` python
    arr=[x.upper() for x in "abc"]
    print(arr)

    ```

    打印结果:`['A', 'B', 'C']`

    获得当前路径,可以用一句代码
    ```python
    import os
    fs=[d for d in os.listdir('.')]
    print(fs)
    ```


    5. 表达式可以赋值给一个变量,实现延迟加载

    ``` python
    g = (2 * x for x in range(10))
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))
    print(next(g))

    打印结果:0,2,4,6,8

    也可以使用循环打印:

    1
    2
    3
    g = (2 * x for x in range(10))
    for x in g:
    print(x)
阅读全文 »

最近想学下数学方面的东西,但发现公式的插入是比较头疼的事情。在Markdown的环境下,有一个latex数学公式官网的写法,用起来很是强大,只要引入下面的js就可以。

1
<script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML' async></script>

x_{11}$$ ,具体的写法如下:

1
$$x_{11}$$

常用的希腊字母写法

|字母|公式||字母|公式|
||\pi\beta\Sigma\gamma\Gamma\delta\Delta\epsilon\varphi\eta\upsilon\phi\Phi\omega\Omega\theta\Theta\lambda\Lambda\mu\nu\xi\partial$$|$$$\partial$$$|

常用的上下标

|字母|公式||字母|公式|
||\sqrt[x]yxix{ij}\dots\cdots$$|$$$\cdots$$$|

运算符

四则运算符(operator) 例如 + - * /等可以直接输入

|字母|公式||字母|公式|
||\times\cap\cup\geq\leq\neq\approx\sum{i=0}^nx_iy_i$$|$$$\sum{i=0}^nxiy_i\sum_1^n\int_1^n\lim{x \to \infty}\frac{y}{x}\equiv$$|$$$\equiv$$$|

阅读全文 »

dict类型的使用

python有一个dict类型,存储格式是key:value的形式,在其他语言有的成为mapDictionary.

1
2
3
>>> dict={"a":1,"b":3}
>>> dict["a"]
1

由于dict是根据key查询数据,所以查询的效率比list要高出不少。

取值的时候,key如果不存在则会报异常。所以为了更安全的使用dict可以使用前判断下:

1
2
>>> "a" in dict
True

或者可以使用get函数,如果不存在,则返回None数据,也可以指定默认值:

1
2
3
4
>>> dict.get("c")
>>> dict.get("c",1)
1
>>>
  1. dict的key必须是不可变对象
  2. dict的内部顺序和存储的先后顺序没有关系
  3. 查找和插入的速度极快,不会随着key的增加而变慢
  4. 需要占用大量的内存,内存浪费多。

dict可以使用pop方法对数据进行删除:

阅读全文 »