Fork me on GitHub
志林的博客


  • 首页

  • 归档

1-5-2-Python进程使用----Process

发表于 2017-09-07 |

multiprocessing

如果你打算编写多进程的服务程序,Unix/Linux无疑是正确的选择。由于Windows没有fork调用,难道在Windows上无法用Python编写多进程的程序?

由于Python是跨平台的,自然也应该提供一个跨平台的多进程支持。multiprocessing模块就是跨平台版本的多进程模块。

multiprocessing模块提供了一个Process类来代表一个进程对象,下面的例子演示了启动一个子进程并等待其结束:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#coding=utf-8
from multiprocessing import Process
import os

# 子进程要执行的代码
def run_proc(name):
print('子进程运行中,name= %s ,pid=%d...' % (name, os.getpid()))

if __name__=='__main__':
print('父进程 %d.' % os.getpid())
p = Process(target=run_proc, args=('test',))
print('子进程将要执行')
p.start()
p.join()
print('子进程已结束')

运行结果:
image.png

说明

  • 创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动,这样创建进程比fork()还要简单。
  • join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。

Process语法结构如下:

Process([group [, target [, name [, args [, kwargs]]]]])

  • target:表示这个进程实例所调用对象;

  • args:表示调用对象的位置参数元组;

  • kwargs:表示调用对象的关键字参数字典;

  • name:为当前进程实例的别名;

  • group:大多数情况下用不到;

Process类常用方法:

  • is_alive():判断进程实例是否还在执行;

  • join([timeout]):是否等待进程实例执行结束,或等待多少秒;

  • start():启动进程实例(创建子进程);

  • run():如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法;

  • terminate():不管任务是否完成,立即终止;

Process类常用属性:

  • name:当前进程实例别名,默认为Process-N,N为从1开始递增的整数;

  • pid:当前进程实例的PID值;

实例1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

from multiprocessing import Process
import os
from time import sleep

# 子进程要执行的代码
def run_proc(name, age, **kwargs):
for i in range(10):
print('子进程运行中,name= %s,age=%d ,pid=%d...' % (name, age,os.getpid()))
print(kwargs)
sleep(0.5)

if __name__=='__main__':
print('父进程 %d.' % os.getpid())
p = Process(target=run_proc, args=('test',18), kwargs={"m":20})
print('子进程将要执行')
p.start()
sleep(1)
p.terminate()
p.join()
print('子进程已结束')

运行结果:

1
2
3
4
5
6
7
父进程 21378.
子进程将要执行
子进程运行中,name= test,age=18 ,pid=21379...
{'m': 20}
子进程运行中,name= test,age=18 ,pid=21379...
{'m': 20}
子进程已结束

实例2

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
50
51
52
53

#coding=utf-8
from multiprocessing import Process
import time
import os

#两个子进程将会调用的两个方法
def worker_1(interval):
print("worker_1,父进程(%s),当前进程(%s)"%(os.getppid(),os.getpid()))
t_start = time.time()
time.sleep(interval) #程序将会被挂起interval秒
t_end = time.time()
print("worker_1,执行时间为'%0.2f'秒"%(t_end - t_start))

def worker_2(interval):
print("worker_2,父进程(%s),当前进程(%s)"%(os.getppid(),os.getpid()))
t_start = time.time()
time.sleep(interval)
t_end = time.time()
print("worker_2,执行时间为'%0.2f'秒"%(t_end - t_start))

#输出当前程序的ID
print("进程ID:%s"%os.getpid())

#创建两个进程对象,target指向这个进程对象要执行的对象名称,
#args后面的元组中,是要传递给worker_1方法的参数,
#因为worker_1方法就一个interval参数,这里传递一个整数2给它,
#如果不指定name参数,默认的进程对象名称为Process-N,N为一个递增的整数
p1=Process(target=worker_1,args=(2,))
p2=Process(target=worker_2,name="dongGe",args=(1,))

#使用"进程对象名称.start()"来创建并执行一个子进程,
#这两个进程对象在start后,就会分别去执行worker_1和worker_2方法中的内容
p1.start()
p2.start()

#同时父进程仍然往下执行,如果p2进程还在执行,将会返回True
print("p2.is_alive=%s"%p2.is_alive())

#输出p1和p2进程的别名和pid
print("p1.name=%s"%p1.name)
print("p1.pid=%s"%p1.pid)
print("p2.name=%s"%p2.name)
print("p2.pid=%s"%p2.pid)

#join括号中不携带参数,表示父进程在这个位置要等待p1进程执行完成后,
#再继续执行下面的语句,一般用于进程间的数据同步,如果不写这一句,
#下面的is_alive判断将会是True,在shell(cmd)里面调用这个程序时
#可以完整的看到这个过程,大家可以尝试着将下面的这条语句改成p1.join(1),
#因为p2需要2秒以上才可能执行完成,父进程等待1秒很可能不能让p1完全执行完成,
#所以下面的print会输出True,即p1仍然在执行
p1.join()
print("p1.is_alive=%s"%p1.is_alive())

执行结果:

1
2
3
4
5
6
7
8
9
10
11
12

进程ID:19866
p2.is_alive=True
p1.name=Process-1
p1.pid=19867
p2.name=dongGe
p2.pid=19868
worker_1,父进程(19866),当前进程(19867)
worker_2,父进程(19866),当前进程(19868)
worker_2,执行时间为'1.00'秒
worker_1,执行时间为'2.00'秒
p1.is_alive=False

#进程的创建-Process子类

创建新的进程还能够使用类的方式,可以自定义一个类,继承Process类,每次实例化这个类的时候,就等同于实例化一个进程对象,请看下面的实例:

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
from multiprocessing import Process
import time
import os

#继承Process类
class Process_Class(Process):
#因为Process类本身也有__init__方法,这个子类相当于重写了这个方法,
#但这样就会带来一个问题,我们并没有完全的初始化一个Process类,所以就不能使用从这个类继承的一些方法和属性,
#最好的方法就是将继承类本身传递给Process.__init__方法,完成这些初始化操作
def __init__(self,interval):
Process.__init__(self)
self.interval = interval

#重写了Process类的run()方法
def run(self):
print("子进程(%s) 开始执行,父进程为(%s)"%(os.getpid(),os.getppid()))
t_start = time.time()
time.sleep(self.interval)
t_stop = time.time()
print("(%s)执行结束,耗时%0.2f秒"%(os.getpid(),t_stop-t_start))

if __name__=="__main__":
t_start = time.time()
print("当前程序进程(%s)"%os.getpid())
p1 = Process_Class(2)
#对一个不包含target属性的Process类执行start()方法,就会运行这个类中的run()方法,所以这里会执行p1.run()
p1.start()
p1.join()
t_stop = time.time()
print("(%s)执行结束,耗时%0.2f"%(os.getpid(),t_stop-t_start))

1-5-1-Python进程使用----fork

发表于 2017-09-06 |

1.进程的创建-fork

Python的os模块封装了常见的系统调用,其中就包括fork,可以在Python程序中轻松创建子进程:

import os

# 注意,fork函数,只在Unix/Linux/Mac上运行,windows不可以
pid = os.fork()

if pid == 0:
    print('哈哈1')
else:
    print('哈哈2')

运行结果:
3.gif

说明:
程序执行到os.fork()时,操作系统会创建一个新的进程(子进程),然后复制父进程的所有信息到子进程中
然后父进程和子进程都会从fork()函数中得到一个返回值,在子进程中这个值一定是0,而父进程中是子进程的 id号
在Unix/Linux操作系统中,提供了一个fork()系统函数,它非常特殊。

普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。

子进程永远返回0,而父进程返回子进程的ID。

这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID。

2. getpid()、getppid()

1
2
3
4
5
6
7
8
9
10
11
12
import os

rpid = os.fork()
if rpid<0:
print("fork调用失败。")
elif rpid == 0:
print("我是子进程(%s),我的父进程是(%s)"%(os.getpid(),os.getppid()))
x+=1
else:
print("我是父进程(%s),我的子进程是(%s)"%(os.getpid(),rpid))

print("父子进程都可以执行这里的代码")

运行结果:

我是父进程(19360),我的子进程是(19361)
父子进程都可以执行这里的代码
我是子进程(19361),我的父进程是(19360)
父子进程都可以执行这里的代码

3.多进程修改全局变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#coding=utf-8
import os
import time

num = 0

# 注意,fork函数,只在Unix/Linux/Mac上运行,windows不可以
pid = os.fork()

if pid == 0:
num+=1
print('哈哈1---num=%d'%num)
else:
time.sleep(1)
num+=1
print('哈哈2---num=%d'%num)

运行结果:
哈哈1—num=1
哈哈2—num=1

总结:多进程中,每个进程中所有数据(包括全局变量)都各有拥有一份,互不影响

4. 多次fork问题

如果在一个程序,有2次的fork函数调用,是否就会有3个进程呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

#coding=utf-8
import os
import time

# 注意,fork函数,只在Unix/Linux/Mac上运行,windows不可以
pid = os.fork()
if pid == 0:
print('哈哈1')
else:
print('哈哈2')

pid = os.fork()
if pid == 0:
print('哈哈3')
else:
print('哈哈4')

time.sleep(1)

运行结果:
哈哈2
哈哈4
哈哈3
哈哈1
哈哈4
哈哈3

说明:

image.png

父子进程的执行顺序: 父进程、子进程执行顺序没有规律,完全取决于操作系统的调度算法

1-4-ubuntu安装最新稳定版本的node及npm

发表于 2017-09-05 |

背景


通过ubuntu官方apt安装工具安装的node是最新LTS版本的,而本人是个有点强迫症的人,喜欢追求新的东西,也就是想方设法想要去安装最新版本的node,所以本文也就产生了,附上ubuntu安装node和npm的命令行命令:

1
2
sudo apt install nodejs-legacy
sudo apt install npm

最新版本安装方法


  1. 安装npm
    1
    sudo apt install npm

2、升级npm为最新版本

1
sudo npm install npm@latest -g

此时通过npm -v可以发现npm版本号为最新版本3.10.3;
3、安装用于安装nodejs的模块n

1
sudo npm install -g n

4、然后通过n模块安装指定版本的nodejs,n模块更多介绍请参考官方文档

1
2
3
4
5
6
//安装官方最新版本
sudo n latest
//安装官方稳定版本
sudo n stable
//安装官方最新LTS版本
sudo n lts

我们通过安装稳定版本的nodejs,然后通过node -v可以发现node安装成功,并且版本号为v6.2.0稳定版本

三步搞定electron-vue-软件自动更新

发表于 2017-09-04 |

image.png

  1. 安装依赖npm i electron-updater,package.json配置build下publish参数如下:
    image.png

  2. 主进程添加代码

    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
    50
    51
    52
    import { autoUpdater } from 'electron-updater'

    // 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
    !function updateHandle() {
    let message = {
    error: '检查更新出错',
    checking: '正在检查更新……',
    updateAva: '检测到新版本,正在下载……',
    updateNotAva: '现在使用的就是最新版本,不用更新',
    };
    const os = require('os');
    const uploadUrl = "http://61.4.184.177:7799/download/"; // 下载地址,不加后面的**.exe
    autoUpdater.setFeedURL(uploadUrl);
    autoUpdater.on('error', function (error) {
    sendUpdateMessage(message.error)
    });
    autoUpdater.on('checking-for-update', function () {
    sendUpdateMessage(message.checking)
    });
    autoUpdater.on('update-available', function (info) {
    sendUpdateMessage(message.updateAva)
    });
    autoUpdater.on('update-not-available', function (info) {
    sendUpdateMessage(message.updateNotAva)
    });

    // 更新下载进度事件
    autoUpdater.on('download-progress', function (progressObj) {
    mainWindow.webContents.send('downloadProgress', progressObj)
    })
    autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {

    ipcMain.on('isUpdateNow', (e, arg) => {
    console.log(arguments);
    console.log("开始更新");
    //some code here to handle event
    autoUpdater.quitAndInstall();
    });

    mainWindow.webContents.send('isUpdateNow')
    });

    ipcMain.on("checkForUpdate",()=>{
    //执行自动更新检查
    autoUpdater.checkForUpdates();
    })
    }()

    // 通过main进程发送事件给renderer进程,提示更新信息
    function sendUpdateMessage(text) {
    mainWindow.webContents.send('message', text)
    }
  3. 渲染进程添加代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    created(){
    const _this = this
    _this.$electron.ipcRenderer.send("checkForUpdate");
    _this.$electron.ipcRenderer.on("message", (event, text) => {
    console.log(arguments);
    _this.tips = text;
    alert(text)
    });
    _this.$electron.ipcRenderer.on("downloadProgress", (event, progressObj)=> {
    console.log(progressObj);
    _this.downloadPercent = progressObj.percent || 0;
    });
    _this.$electron.ipcRenderer.on("isUpdateNow", () => {
    _this.$electron.ipcRenderer.send("isUpdateNow");
    });
    },
    beforeDestroy(){
    // this.$electron.ipcRenderer.removeAll(["message", "downloadProgress", "isUpdateNow"]);
    }

打包,将生成的exe文件和latest.yml文件上传至服务器
image.png

引用 electron-vue autoupdater

1-3-Linux常用服务器构建-ssh和scp

发表于 2017-09-04 |

1.ssh

<1>ssh介绍

SSH为Secure Shell的缩写,由 IETF 的网络工作小组(Network Working Group)所制定;SSH 为建立在应用层和传输层基础上的安全协议。

SSH是目前较可靠,专为远程登录会话和其他网络服务提供安全性的协议。常用于远程登录,以及用户之间进行资料拷贝。

利用SSH协议可以有效防止远程管理过程中的信息泄露问题。SSH最初是 UNIX 系统上的一个程序,后来又迅速扩展到其他操作平台。SSH 在正确使用时可弥补网络中的漏洞。SSH 客户端适用于多种平台。几乎所有 UNIX 平台—包括 HP-UX、Linux、AIX、Solaris、Digital UNIX、Irix,以及其他平台,都可运行SSH。

使用SSH服务,需要安装相应的服务器和客户端。客户端和服务器的关系:如果,A机器想被B机器远程控制,那么,A机器需要安装SSH服务器,B机器需要安装SSH客户端。

<2>安装ssh

A.安装ssh服务器

1
sudo apt-get install openssh-server

B.远程登陆

1
ssh 用户名@IP

使用ssh访问,如访问出现错误。可查看是否有该文件 ~/.ssh/known_ssh 尝试删除该文件解决。

<3>使用ssh连接服务器

SSH 告知用户,这个主机不能识别,这时键入”yes”,SSH 就会将相关信息,写入” ~/.ssh/know_hosts” 中,再次访问,就不会有这些信息了。然后输入完口令,就可以登录到主机了。

image.png

2.scp

远程拷贝文件,scp -r 的常用方法:

1.使用该命令的前提条件要求目标主机已经成功安装openssh-server

1
如没有安装使用 sudo apt-get install openssh-server 来安装

2.使用格式:

1
2
3
4
5
6
scp -r 目标用户名@目标主机IP地址:/目标文件的绝对路径  /保存到本机的绝对/相对路径

举例:
scp -r itcast@192.168.1.100:/home/itcast/QQ_dir/ ./mytest/lisi

在后续会提示输入“yes”此时,只能输“yes”而不能简单输入“Y”

拷贝单个文件可以不加 -r参数,拷贝目录必须要加。

本地文件复制到远程:

1
2
3
scp FileName RemoteUserName@RemoteHostIp:RemoteFile
scp FileName RemoteHostIp:RemoteFolder
scp FileName RemoteHostIp:RemoteFile

本地目录复制到远程:

1
2
scp -r FolderName RemoteUserName@RemoteHostIp:RemoteFolder
scp -r FolderName RemoteHostIp:RemoteFolder

远程文件复制到本地:

1
2
3
scp RemoteUserName@RemoteHostIp:RemoteFile FileName
scp RemoteHostIp:RemoteFolder FileName
scp RemoteHostIp:RemoteFile FileName

远程目录复制到本地:

1
2
scp -r RemoteUserName@RemoteHostIp:RemoteFolder FolderName
scp -r RemoteHostIp:RemoteFolder FolderName

image.png

1-2-Linux常用服务器构建-ftp服务器

发表于 2017-09-03 |

ftp服务器

FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”。

用于Internet上的控制文件的双向传输。

同时,它也是一个应用程序(Application)。基于不同的操作系统有不同的FTP应用程序,而所有这些应用程序都遵守同一种协议以传输文件。

在FTP的使用当中,用户经常遇到两个概念:”下载”(Download)和”上传”(Upload)。

“下载”文件就是从远程主机拷贝文件至自己的计算机上;

“上传”文件就是将文件从自己的计算机中拷贝至远程主机上。用Internet语言来说,用户可通过客户机程序向(从)远程主机上传(下载)文件。

image.png

1.安装vsftpd服务器

1
sudo apt-get install vsftpd

image.png
image.png

2.配置vsftpd.conf文件

1
sudo vi /etc/vsftpd.conf

image.png

image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png

image.png

3.测试上传功能,登陆ftp服务器

1
ftp  IP

image.png

4.上传命令,可以把文件上传到ftp服务器

1
put somefile

5.下载命令,可以把ftp服务器上的文件下载到本地

1
get somefile

图形界面的ftp客户端(filezilla)

image.png

1-1-Linux常用服务器构建-samba

发表于 2017-09-02 |

1. 介绍

Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,能够完成在windows、mac操作系统下访问linux系统下的共享文件

2. 安装

使用apt命令安装samba
image.png

3. 配置

3.1 创建存放共享文件的路径

在home路径下操作:
image.png
修改其权限:

image.png
修改samba的配置文件:
image.png
image.png

3.2 创建samba账户

image.png
image.png

4 重启samba

当对配置进行了更新,需要重启samba软件后才可生效

重启命令如下:

image.png

5. 访问共享文件

5.1 mac下访问方式

image.png

image.png

image.png

image.png

5.2 windows下访问方式

image.png
image.png

1-0-ubuntu软件安装与卸载

发表于 2017-09-01 |

ubuntu软件安装与卸载

更新Ubuntu软件下载地址

1. 寻找国内镜像源

所谓的镜像源:可以理解为提供下载软件的地方,比如Android手机上可以下载软件的91手机助手;iOS手机上可以下载软件的AppStore

image.png

image.png
image.png
image.png

2. 备份Ubuntu默认的源地址

1
sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup

image.png

3. 更新源服务器列表

image.png

image.png
image.png

4. 更新源

做完此步骤之后,就可以进行apt-get install 下载了
image.png
image.png
image.png

Ubuntu软件操作的相关命令

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
sudo apt-get update  更新源

sudo apt-get install package 安装包

sudo apt-get remove package 删除包

sudo apt-cache search package 搜索软件包

sudo apt-cache show package 获取包的相关信息,如说明、大小、版本等

sudo apt-get install package --reinstall 重新安装包

sudo apt-get -f install 修复安装

sudo apt-get remove package --purge 删除包,包括配置文件等

sudo apt-get build-dep package 安装相关的编译环境

sudo apt-get upgrade 更新已安装的包

sudo apt-get dist-upgrade 升级系统

sudo apt-cache depends package 了解使用该包依赖那些包

sudo apt-cache rdepends package 查看该包被哪些包依赖

sudo apt-get source package 下载该包的源代码

sudo apt-get clean && sudo apt-get autoclean 清理无用的包

sudo apt-get check 检查是否有损坏的依赖
123

Jean1024

28 日志
4 标签
GitHub E-Mail Google Twitter StackOverflow YouTube JianShu
© 2018 Jean1024
由 Hexo 强力驱动
|
主题 — NexT.Gemini v5.1.4