[Python-13/100] 进程和线程(Process and Thread)

版权声明:公众号:Fresh Site。QQ群:690274159。转载我的博文时,请附上转载地址,谢谢!^_^我是嘻哈程序猿freshman。 https://blog.csdn.net/wuhongxia29/article/details/90762944

Day13 进程和线程


参考资料:
1.github-100-days-进程和线程
2.廖雪峰-进程和线程
3.Daemon is not daemon, but what is it?
推荐工具:科赛

概念

  • 进程:程序,fork、spawn,IPC(管道、信号、套接字、共享内存区等)
  • 线程:CPU调度执行单元(1-n:进程-线程)

多进程

单进程与多进程对比

# demo1.0
# 普通
from random import randint
from time import time, sleep


def download_task(filename):
    print('开始下载。。。%s' % filename)
    time_to_download = randint(5, 10)
    sleep(time_to_download)
    print('%s下载完成!耗时%d秒' % (filename, time_to_download))

def main():
    start = time()
    download_task('python入门到住院')
    download_task('Peking Hot.avi')
    end = time()
    print('总耗时%.2f' % (end-start))
    
main()

开始下载。。。python入门到住院
python入门到住院下载完成!耗时5秒
开始下载。。。Peking Hot.avi
Peking Hot.avi下载完成!耗时5秒
总耗时10.01

# demo1.1
# 多进程
from multiprocessing import Process
from os import getpid
from random import randint
from time import time, sleep


def download_task(filename):
    print('启动下载进程,进程号[%d]' % getpid())
    print('开始下载%s...' % filename)
    time_to_download = randint(5, 10)
    sleep(time_to_download)
    print('%s下载完成,耗时%d秒' % (filename, time_to_download))
    
    
def main():
    start = time()
    p1 = Process(target=download_task, args=('Python入门到住院.pdf', ))
    p1.start()
    p2 = Process(target=download_task, args=('Peking Hot.avi', ))
    p2.start()
    p1.join()
    p2.join()
    end = time()
    print('共耗时%.2f秒' % (end-start))
    
    
main()

启动下载进程,进程号[129]
开始下载Python入门到住院.pdf…
启动下载进程,进程号[132]
开始下载Peking Hot.avi…
Peking Hot.avi下载完成,耗时6秒
Python入门到住院.pdf下载完成,耗时7秒
共耗时7.09秒

例子

我们启动两个进程,一个输出Ping,一个输出Pong,两个进程输出的Ping和Pong加起来一共10个。听起来很简单吧,但是如果这样写可是错的哦。

from multiprocessing import Process
from time import sleep


counter = 0


def sub_task(string):
    global counter
    while counter < 10:
        print(('[%d]'+string) % counter, end='\t', flush=True)  # flush=True,将信息立刻打印(https://blog.csdn.net/u013985241/article/details/86653356)
        
        counter += 1
        sleep(0.01)
    
def main():
    Process(target=sub_task, args= ('Ping', )).start()
    Process(target=sub_task, args= ('Pong', )).start()
        
    
main()

[0]Ping [0]Pong [1]Ping [1]Pong [2]Ping [2]Pong [3]Ping [3]Pong [4]Ping [4]Pong [5]Ping [5]Pong [6]Ping [6]Pong [7]Ping [7]Pong [8]Ping [8]Pong [9]Ping [9]Pong


多线程

例1

# demo1.0
# 单线程
from random import randint
from threading import Thread
from time import time, sleep


def download(filename):
    print('开始下载%s...' % filename)
    time_to_download = randint(5, 10)
    sleep(time_to_download)
    print('%s下载完成,耗时%.2f秒' % (filename, time_to_download))
    
    
def main():
    start = time()
    t1 = Thread(target=download, args=('Pyton从入门到住院', ))
    t1.start()
    t2 = Thread(target=download, args=('Pyton从入门到精通', ))
    t2.start()
    t1.join()  # 阻塞,主等子。超timeout,主关子(https://blog.csdn.net/zhiyuan_2007/article/details/48807761)
    t2.join()
    end = time()
    print('耗时:%.2f' % (end-start))
    
    
main()

开始下载Pyton从入门到住院…
开始下载Pyton从入门到精通…
Pyton从入门到住院下载完成,耗时9.00秒Pyton从入门到精通下载完成,耗时9.00秒
耗时:9.01

例2

# 自定义线程类
from random import randint
from threading import Thread
from time import time, sleep


class DownloadTask(Thread):
    
    def __init__(self, filename):
        super().__init__()
        self._filename = filename
        
    def run(self):
        print('开始下载%s...' % self._filename)
        time_to_download = randint(5, 10)
        sleep(time_to_download)
        print('%s下载完成,耗时%.2f秒' % (self._filename, time_to_download))
        

def main():
    start = time()
    t1 = DownloadTask('Python1')
    t1.start()
    t2 = DownloadTask('Python2')
    t2.start()
    t1.join()
    t2.join()
    end = time()
    print('耗时%.2f' % (end-start))
    

main()

开始下载Python1…
开始下载Python2…
Python2下载完成,耗时7.00秒
Python1下载完成,耗时8.00秒
耗时8.01

例3

# 用Lock处理临界资源问题
# GIL(Global Interpreter Lock)(全局解释器锁)
# 每100条字节码(http://python.jobbole.com/56761/),自动释放GIL锁
from time import sleep
from threading import Thread, Lock


class Account(object):
    
    def __init__(self):
        self._balance = 0
        self._lock = Lock()
        
    def deposit(self, money):
        self._lock.acquire()  # 先获取锁才能执行后续代码
        try:
            new_balance = self._balance + money  # 计算存款后的余额
            sleep(0.01)  # 模拟受理存款业务需要0.01秒的时间
            self._balance = new_balance  # 修改账户余额
        finally:
            self._lock.release()  # 保证正常异常锁都能释放
        
    @property
    def balance(self):
        return self._balance
        
        
class AddMoneyThread(Thread):
    
    def __init__(self, account, money):
        super().__init__()
        self._account = account
        self._money = money
        
    def run(self):
        self._account.deposit(self._money)
        

def money():
    account = Account()
    threads = []
    for _ in range(100):  # 创建100个存款的线程向同一个账户存钱
        t = AddMoneyThread(account, 1)
        threads.append(t)
        t.start()
    # 等所有存款线程执行完毕
    for t in threads:
        t.join()
    print('余额:¥%d元' % account.balance)
    

money()    

余额:¥100元


多进/线程的选择

稳定 资源 速度 例子
进程 较好 较慢 早期Apache服务器(现在是混合[进+线])
线程 较差 较快 早期IIS服务器(现在是混合)

影响因素

1.切换

  • 多任务切换
  • 环境保存、恢复

2.任务类型

类型 占资源 速度 特点 适用 语言 例子
计算密集 效率低 多次任务切换耗时 多进程 C 视频编解码、格式转换等
I/O密集 慢于内存、CPU 多线程 Python(脚本) 网络、存储介质I/O

单线程+异步I/O

协程:单线程+异步I/O
优点:充分利用多核CPU,效率高
例子:Nginx服务器、Node.js开发的服务器程序等
max:多进程+协程


  • Python从入门到住院/放弃/颈椎病

报错

1.类型错误 :在字符串格式下并没有转换所有参数
TypeError: not all arguments converted during string formatting

# 错误
print('开始下载。。。' % filename)

# 正确
print('开始下载。。。%s' % filename)

2.类型错误:download_task()给予了一位参数位置,但是赋值14位
TypeError: download_task() takes 1 positional argument but 14 were given

# 错误
p2 = Process(target=download_task, args=('Peking Hot.avi'))

# 正确
# 元组只有一个参数时,需要在末尾加','
p2 = Process(target=download_task, args=('Peking Hot.avi', ))

3.类型错误:描述符“init”的super对象需要一个参数
TypeError: descriptor ‘init’ of ‘super’ object needs an argument

# 错误
class AddMoneyThread(Thread):
    
    def __init__(self, account, money):
        super.__init__()
        self._account = account
        self._money = money

# 正确
class AddMoneyThread(Thread):
    
    def __init__(self, account, money):
        super().__init__()
        self._account = account
        self._money = money

英语积累

1.Because I think the point of this assignment is you’re not supposed to leave threads unlocked.
因为我认为这个任务的重点是你不应该解锁线程。

猜你喜欢

转载自blog.csdn.net/wuhongxia29/article/details/90762944