栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

【Linux】写个脚本实现简单的程序单例运行功能

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Linux】写个脚本实现简单的程序单例运行功能

需求

写了个爬虫脚本放到服务器上定时运行,当脚本碰到耗时的任务阻塞太久的时候可能下一次定时调用会发生,这会导致同时运行的脚本数量大于一个,可能会造成数据库数据重复等问题。现在想解决这个问题,但是并不想更改爬虫脚本相关的代码。

分析需求不难看出同时运行的爬虫脚本不能大于一个,由于脚本是通过定时任务启动(这里假设是 cron),我们可以在启动爬虫的指令上动手脚,在启动爬虫之前先判断是否有爬虫脚本运行,如果有则不启动爬虫。

实现方法1:ps(失败)

最直观的方法是通过 ps 查找指定名称的进程,然后判断进程是否存在,如果存在则不启动脚本:

TASK=`ps aux | grep sh /root/run_crawler.sh | grep -v grep`
if [ "$TASK" = "" ]; then
  # 执行一些耗时的任务
  python run.py 
fi

如示例代码所示,这个脚本的主要问题在 grep 查找进序上,因为通过 cron 启动这个脚本的时候也会启动同名的进程,所以在查找之前该进程就已经被创建,而根据脚本“进程不存在才执行”的逻辑,这段脚本永远不会执行 if 段里面的内容。

实现方法2:判断指定文件是否存在

我们可以在运行脚本之前判断一个指定的文件是否存在,如果存在表示脚本正在运行,否则运行脚本并创建该文件,脚本运行结束后删除该文件,伪代码如下:

filename = 'LOCK'

if filename 不存在:
  创建文件(filename)
  # 执行耗时操作
  python run.py
  删除文件(filename)

示例 bash 代码如下:

LOCK="LOCK.temp"
if [ ! -f "$LOCK" ]; then
  touch $LOCK
  python run_crawlers.py
  sleep 2
  python push_message.py
  rm -rf $LOCK

这种写法有两个主要的问题:

  1. 文件名可能会和本地文件冲突 - 可以通过生成时间戳文件名等方法解决
  2. 可能产生 if 内脚本永远无法运行的 bug
    第二个问题产生的原因是当我们执行 if 段的代码时,创建了 lock 文件,但是执行过程中脚本的运行被打断,导致 lock 文件无法被自动删除,除非手动删除否则该脚本永远不会执行。

第二个问题的解决方法
增加一个超时机制,即如果 lock 存在的时间超过指定时间,删除 lock,这里用到了 stat 指令用来获取文件创建的时间戳,date +%s 获取当前时间戳,完整代码如下:

LOCK="LOCK.temp"
if [ ! -f "$LOCK" ]; then
  touch $LOCK
  # 执行一些耗时操作
  python main.py
  rm -rf $LOCK
else
  ts=`stat -c %Y $LOCK`
  now=`date +%s`
  # 超时时间为 1800s (30min)
  if [ $[ $now - $ts ] -gt 1800 ]; then
    rm -rf $LOCK
    echo "Lock expired, deleted"
  fi
fi
总结

以上提供了一种单例运行的思路,实际上还有很多其他的方法能够避免数据重复写的问题,可以根据自己的实际情况选择。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/998405.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号