一个电子围栏需求的脚本记录

需求:系统对接了厂家的GPS数据,基于这些GPS数据,过滤出指定区域的数据

从网上找到了一个电子围栏的python脚本,现在需要的是循环取数据判断是否在指定区域,在指定区域就把这部分数据拿出来放到另外一个库表

碰到的其中一个问题是脚本的效率问题,以5W条数据来测试

脚本1:使用cur.fetchone(),逐条读取数据,逐条判断,逐条插入列表,批量入库,批量commit

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import math
import MySQLdb
import time
ISOTIMEFORMAT=‘%Y-%m-%d %X‘
print ‘start‘,‘:‘,time.strftime(ISOTIMEFORMAT, time.localtime())
lnglatlist = []
data = ‘[{"name":"广本黄埔工厂","points":[{"lng":113.642124,"lat":23.167372},{"lng":113.636176,"lat":23.175162},{"lng":113.644930,"lat":23.179870},{"lng":113.652108,"lat":23.173823}],"type":0}]‘
data = json.loads(data)
if ‘points‘ in data[0]:
    for point in data[0][‘points‘]:
        #print(str(point[‘lng‘])+" "+str(point[‘lat‘]))
        lnglat = []
        lnglat.append(float(str(point[‘lng‘])))
        lnglat.append(float(str(point[‘lat‘])))
        lnglatlist.append(lnglat)
def windingNumber(point, poly):
    poly.append(poly[0])
    px = point[0]
    py = point[1]
    sum = 0
    length = len(poly)-1

    for index in range(0,length):
        sx = poly[index][0]
        sy = poly[index][1]
        tx = poly[index+1][0]
        ty = poly[index+1][1]

        #点与多边形顶点重合或在多边形的边上
        if((sx - px) * (px - tx) >= 0 and (sy - py) * (py - ty) >= 0 and (px - sx) * (ty - sy) == (py - sy) * (tx - sx)):
            return "on"
        #点与相邻顶点连线的夹角
        angle = math.atan2(sy - py, sx - px) - math.atan2(ty - py, tx - px)

        #确保夹角不超出取值范围(-π 到 π)
        if(angle >= math.pi):
            angle = angle - math.pi * 2
        elif(angle <= -math.pi):
            angle = angle + math.pi * 2
        sum += angle

        #计算回转数并判断点和多边形的几何关系
    result = ‘out‘ if int(sum / math.pi) == 0 else ‘in‘
    return result

################循环取GPS数据##########################
conn=MySQLdb.connect(user=‘root‘,passwd=‘XXX‘,host=‘XXX‘,charset="utf8") #连接到mysql
cur=conn.cursor()
conn.select_db(‘XXX‘)
cur.execute("select id,sim,alarm,status,latitude,longitude,asl,speed,direction,sample_time,attch_msg,create_time,car_no from gps_msg where sample_time>=‘2019-04-10 18:00:00‘ and sample_time<‘2019-04-10 20:00:00‘ limit 50000")
####################第一种方式########################
count=1
scope_gps_list=[]
while count<=50000:    #这种方式,这个数量不能比SQL的数据量小,不然会报错
    gps_data_per=cur.fetchone()
    # print gps_data_per
    point=gps_data_per[5].split(",")+gps_data_per[4].split(",")  #取出每条数据的经纬度,split()转换成列表
    point=map(float,point) #字符串类型转换成浮点型
    # print point
    # print count
    if count in(10000,20000,30000,40000,50000):
        print count,‘:‘,time.strftime(ISOTIMEFORMAT, time.localtime())
    # print windingNumber(point,lnglatlist)
    if windingNumber(point,lnglatlist)==‘in‘:
        scope_gps_list.append(gps_data_per)   #生成[(1,2,3),(1,2,3)]
    count=count+1
sqlin="insert into gps_msg_20190411(id,sim,alarm,status,latitude,longitude,asl,speed,direction,sample_time,attch_msg,create_time,car_no) values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
cur.executemany(sqlin,scope_gps_list)
conn.commit()
####################第一种方式########################
####################第二种方式########################
# gps_data_all=cur.fetchall()
# count=0
# for gps_data_per in gps_data_all:
    # sqlin="insert into gps_msg_20190411(id,sim,alarm,status,latitude,longitude,asl,speed,direction,sample_time,attch_msg,create_time,car_no) values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
    # point=gps_data_per[5].split(",")+gps_data_per[4].split(",")  #取出每条数据的经纬度,split()转换成列表
    # point=map(float,point) #字符串类型转换成浮点型
    # if windingNumber(point,lnglatlist)==‘in‘:
        # cur.execute(sqlin,gps_data_per)
    # count=count+1
    # print count
# conn.commit()
####################第二种方式########################

cur.close() #关闭游标
conn.close() #关闭数据链接
################循环取GPS数据##########################
print ‘end‘,‘:‘,time.strftime(ISOTIMEFORMAT, time.localtime())

为什么要逐条插入列表?

因为使用cur.fetchone()读取数据后马上去insert into数据,再次cur.fenchone数据,取不到数据

执行效率:30分6秒跑完


start : 2019-04-19 20:30:00
10000 : 2019-04-19 20:31:16        1分16秒
20000 : 2019-04-19 20:34:56        3分40秒
30000 : 2019-04-19 20:41:03        6分6秒
40000 : 2019-04-19 20:49:35        8分32秒
50000 : 2019-04-19 21:00:36        11分1秒
end : 2019-04-19 21:00:36            不到一秒

总结:最后的列表插入数据库很快,不到1秒

脚本2:使用cur.fetchall()先存全部数据,再使用for循环,逐条读取,逐条判断,逐条入库,批量commit

对比脚本1,主要是逐条入库,避免插入到列表,确定下是否插入到列表,列表越来越大导致的慢

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import math
import MySQLdb
import time
ISOTIMEFORMAT=‘%Y-%m-%d %X‘
print ‘start‘,‘:‘,time.strftime(ISOTIMEFORMAT, time.localtime())
lnglatlist = []
data = ‘[{"name":"工厂","points":[{"lng":113.642124,"lat":23.167372},{"lng":113.636176,"lat":23.175162},{"lng":113.644930,"lat":23.179870},{"lng":113.652108,"lat":23.173823}],"type":0}]‘
data = json.loads(data)
if ‘points‘ in data[0]:
    for point in data[0][‘points‘]:
        #print(str(point[‘lng‘])+" "+str(point[‘lat‘]))
        lnglat = []
        lnglat.append(float(str(point[‘lng‘])))
        lnglat.append(float(str(point[‘lat‘])))
        lnglatlist.append(lnglat)
def windingNumber(point, poly):
    poly.append(poly[0])
    px = point[0]
    py = point[1]
    sum = 0
    length = len(poly)-1

    for index in range(0,length):
        sx = poly[index][0]
        sy = poly[index][1]
        tx = poly[index+1][0]
        ty = poly[index+1][1]

        #点与多边形顶点重合或在多边形的边上
        if((sx - px) * (px - tx) >= 0 and (sy - py) * (py - ty) >= 0 and (px - sx) * (ty - sy) == (py - sy) * (tx - sx)):
            return "on"
        #点与相邻顶点连线的夹角
        angle = math.atan2(sy - py, sx - px) - math.atan2(ty - py, tx - px)

        #确保夹角不超出取值范围(-π 到 π)
        if(angle >= math.pi):
            angle = angle - math.pi * 2
        elif(angle <= -math.pi):
            angle = angle + math.pi * 2
        sum += angle

        #计算回转数并判断点和多边形的几何关系
    result = ‘out‘ if int(sum / math.pi) == 0 else ‘in‘
    return result

################循环取GPS数据##########################
conn=MySQLdb.connect(user=‘root‘,passwd=‘XXX‘,host=‘XXX‘,charset="utf8") #连接到mysql
cur=conn.cursor()
conn.select_db(‘XXX‘)
cur.execute("select id,sim,alarm,status,latitude,longitude,asl,speed,direction,sample_time,attch_msg,create_time,car_no from gps_msg where sample_time>=‘2019-04-10 18:00:00‘ and sample_time<‘2019-04-10 20:00:00‘ limit 50000")
####################第一种方式########################
# count=1
# scope_gps_list=[]
# while count<=50000:    #这种方式,这个数量不能比SQL的数据量小,不然会报错
    # gps_data_per=cur.fetchone()
    # point=gps_data_per[5].split(",")+gps_data_per[4].split(",")  #取出每条数据的经纬度,split()转换成列表
    # point=map(float,point) #字符串类型转换成浮点型
    # if count in(10000,20000,30000,40000,50000):
        # print count,‘:‘,time.strftime(ISOTIMEFORMAT, time.localtime())
    # if windingNumber(point,lnglatlist)==‘in‘:
        # scope_gps_list.append(gps_data_per)   #生成[(1,2,3),(1,2,3)]
    # count=count+1
# sqlin="insert into gps_msg_20190411(id,sim,alarm,status,latitude,longitude,asl,speed,direction,sample_time,attch_msg,create_time,car_no) values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
# cur.executemany(sqlin,scope_gps_list)
# conn.commit()
####################第一种方式########################
####################第二种方式########################
gps_data_all=cur.fetchall()
count=0
for gps_data_per in gps_data_all:
    sqlin="insert into gps_msg_20190411(id,sim,alarm,status,latitude,longitude,asl,speed,direction,sample_time,attch_msg,create_time,car_no) values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
    point=gps_data_per[5].split(",")+gps_data_per[4].split(",")  #取出每条数据的经纬度,split()转换成列表
    point=map(float,point) #字符串类型转换成浮点型
    if windingNumber(point,lnglatlist)==‘in‘:
        cur.execute(sqlin,gps_data_per)
    count=count+1
    if count in(10000,20000,30000,40000,50000):
        print count,‘:‘,time.strftime(ISOTIMEFORMAT, time.localtime())
conn.commit()
####################第二种方式########################

cur.close() #关闭游标
conn.close() #关闭数据链接
################循环取GPS数据##########################
print ‘end‘,‘:‘,time.strftime(ISOTIMEFORMAT, time.localtime())

执行效率:29分钟22秒


start : 2019-04-19 21:05:09
10000 : 2019-04-19 21:06:22    1分16秒
20000 : 2019-04-19 21:09:55    3分33秒
30000 : 2019-04-19 21:15:48    5分53秒
40000 : 2019-04-19 21:23:58    8分10秒
50000 : 2019-04-19 21:34:31    10分33秒
end : 2019-04-19 21:34:31        不到1秒

总结,看来不是插入到列表,导致的速度慢

脚本3:使用cur.fetchall()先存全部数据,再使用for循环,逐条读取,逐条判断,逐条入库,逐条commit

对比脚本2,逐条入库,逐条commit,只是做个简单的对比

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import math
import MySQLdb
import time
ISOTIMEFORMAT=‘%Y-%m-%d %X‘
print ‘start‘,‘:‘,time.strftime(ISOTIMEFORMAT, time.localtime())
lnglatlist = []
data = ‘[{"name":"工厂","points":[{"lng":113.642124,"lat":23.167372},{"lng":113.636176,"lat":23.175162},{"lng":113.644930,"lat":23.179870},{"lng":113.652108,"lat":23.173823}],"type":0}]‘
data = json.loads(data)
if ‘points‘ in data[0]:
    for point in data[0][‘points‘]:
        #print(str(point[‘lng‘])+" "+str(point[‘lat‘]))
        lnglat = []
        lnglat.append(float(str(point[‘lng‘])))
        lnglat.append(float(str(point[‘lat‘])))
        lnglatlist.append(lnglat)
def windingNumber(point, poly):
    poly.append(poly[0])
    px = point[0]
    py = point[1]
    sum = 0
    length = len(poly)-1

    for index in range(0,length):
        sx = poly[index][0]
        sy = poly[index][1]
        tx = poly[index+1][0]
        ty = poly[index+1][1]

        #点与多边形顶点重合或在多边形的边上
        if((sx - px) * (px - tx) >= 0 and (sy - py) * (py - ty) >= 0 and (px - sx) * (ty - sy) == (py - sy) * (tx - sx)):
            return "on"
        #点与相邻顶点连线的夹角
        angle = math.atan2(sy - py, sx - px) - math.atan2(ty - py, tx - px)

        #确保夹角不超出取值范围(-π 到 π)
        if(angle >= math.pi):
            angle = angle - math.pi * 2
        elif(angle <= -math.pi):
            angle = angle + math.pi * 2
        sum += angle

        #计算回转数并判断点和多边形的几何关系
    result = ‘out‘ if int(sum / math.pi) == 0 else ‘in‘
    return result

################循环取GPS数据##########################
conn=MySQLdb.connect(user=‘root‘,passwd=‘XXX‘,host=‘XXX‘,charset="utf8") #连接到mysql
cur=conn.cursor()
conn.select_db(‘XXX‘)
cur.execute("select id,sim,alarm,status,latitude,longitude,asl,speed,direction,sample_time,attch_msg,create_time,car_no from gps_msg where sample_time>=‘2019-04-10 18:00:00‘ and sample_time<‘2019-04-10 20:00:00‘ limit 50000")
####################第一种方式########################
# count=1
# scope_gps_list=[]
# while count<=50000:    #这种方式,这个数量不能比SQL的数据量小,不然会报错
    # gps_data_per=cur.fetchone()
    # point=gps_data_per[5].split(",")+gps_data_per[4].split(",")  #取出每条数据的经纬度,split()转换成列表
    # point=map(float,point) #字符串类型转换成浮点型
    # if count in(10000,20000,30000,40000,50000):
        # print count,‘:‘,time.strftime(ISOTIMEFORMAT, time.localtime())
    # if windingNumber(point,lnglatlist)==‘in‘:
        # scope_gps_list.append(gps_data_per)   #生成[(1,2,3),(1,2,3)]
    # count=count+1
# sqlin="insert into gps_msg_20190411(id,sim,alarm,status,latitude,longitude,asl,speed,direction,sample_time,attch_msg,create_time,car_no) values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
# cur.executemany(sqlin,scope_gps_list)
# conn.commit()
####################第一种方式########################
####################第二种方式########################
gps_data_all=cur.fetchall()
count=0
for gps_data_per in gps_data_all:
    sqlin="insert into gps_msg_20190411(id,sim,alarm,status,latitude,longitude,asl,speed,direction,sample_time,attch_msg,create_time,car_no) values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
    point=gps_data_per[5].split(",")+gps_data_per[4].split(",")  #取出每条数据的经纬度,split()转换成列表
    point=map(float,point) #字符串类型转换成浮点型
    if windingNumber(point,lnglatlist)==‘in‘:
        cur.execute(sqlin,gps_data_per)
        conn.commit()
    count=count+1
    if count in(10000,20000,30000,40000,50000):
        print count,‘:‘,time.strftime(ISOTIMEFORMAT, time.localtime())

####################第二种方式########################

cur.close() #关闭游标
conn.close() #关闭数据链接
################循环取GPS数据##########################
print ‘end‘,‘:‘,time.strftime(ISOTIMEFORMAT, time.localtime())

执行效率:


start : 2019-04-19 21:45:11
10000 : 2019-04-19 21:46:30    1分19秒
20000 : 2019-04-19 21:50:10    3分40秒
30000 : 2019-04-19 21:56:09    5分59秒
40000 : 2019-04-19 22:04:30    8分21秒
50000 : 2019-04-19 22:15:12    10分42秒
end : 2019-04-19 22:15:12        不到1秒

总结:逐条commit会降低效率

参考:https://www.cnblogs.com/dong1/p/10220116.html

原文地址:https://www.cnblogs.com/fuqu/p/10739194.html

时间: 2024-10-04 00:28:13

一个电子围栏需求的脚本记录的相关文章

分享一个R语言的脚本【时间记录】

分享一个R语言的脚本 最近捣弄下一个R语言的脚本,不知道大家有没有看过<奇特的一生>这本书,我高中看了后,高三就山寨了柳比歇夫大神的方法,记录时间开销.个人感觉是挺有用的. 脚本就是把下面的这种excel文件导入并自动转化成饼形图,输出图片到本地. 代码在此: record <- read.table("Book1.csv", header=TRUE,sep=",", fill=TRUE); library(ggplot2); new_sum<

一个渲染需求

用unity3d做游戏也有一段时间了,这周有一个渲染的需求,用到的技术不算很深,但确实也比较繁琐,值得记录一下. 需求大概是这样的,有四层图,我们称为A,B,C,D四层.他们的Blend顺序是A->B->C->D,其中C对D的Blend算法使用的是PS中的叠加算法,B->C,D是替换,A->B,C,D也是PS的叠加.这个问题的难点在于两部分:第一,有部分层的Blend算法是使用的PS的叠加,而叠加公式为(B < 128) ? (2 * A * B / 255):(255

shell 脚本记录

shell脚本中执行另一个shell脚本 可以在一个shell脚本中执行另一个shell脚本(或非可执行文件,主要用于取得一些变量的值),方法是: . 文件名(包括路径) 或 变量=文件名(包括路径) . $变量 注意,圆点后面有个空格. 这样,在本shell脚本的后面部分就可以引用其他文件中声明的一些变量. linux手动添加开机启动的服务 执行下cat /etc/rc.local看看这个文件,不需要任何帮助手册和文档,看完这个文件后你就有更好的办法来添加一个开机启动的服务. #!/bin/s

PADS 脚本记录:关于 getObjects

PADS 脚本记录:关于 getObjects GetObjects(plogObjectTypeComponent, "ZBOM*", False) 返回的一个对象,所有 ZBOM Commponets 对象,可以使用 count 计算对象数量. 如果使用其中一个,需要用 For Each 循环出. 原文地址:https://www.cnblogs.com/F4NNIU/p/10391954.html

一个简单的shell脚本

一个简单的shell脚本 编写 假设我想知道目前系统上有多少人登录,使用who命令可以告诉你现在系统有谁登录: 1.[[email protected] ~]$ who2.KANO tty1 2016-02-15 01:47 (:0)3.KANO pts/0 2016-02-15 01:48 (kelvin) 当然在个人电脑上,所列出来的列表可能只有上面这么短.但是在一些大型.多用户的系统上,所列出的列表就可能很长.这个时候我们可以使用自动计算用户总数.wc是一个字数计算程序,它可以计算出行数(

一个计算的小脚本

[[email protected] cailu]# cat urfile 1 a2 b3 a1 d[[email protected] cailu]# awk '{a[$1]=a[$1]?a[$1]OFS$2:$2}END{for(i in a)print i,a[i]}' urfile 1 a d2 b3 a 一个计算的小脚本,布布扣,bubuko.com

13 一个Mysql自动备份脚本

写了一个Mysql备份的脚本,大家看看,有什么不妥地方. 这是我写的第一个Shell脚本,大家帮忙看看, 有谁需要的,我可以发给他. 可以将这个脚本放进crontab,每天凌晨执行一次,自动备份 这个脚本每天最多只执行一次,而且只保留最近五天的备份在服务器上. 代码: #!/bin/bash #This is a ShellScript For Auto DB Backup #Powered by aspbiz #2004-09 #Setting #设置数据库名,数据库登录名,密码,备份路径,日

一个lvs的安装脚本

一个lvs的安装脚本,大家可以参考一下 说明: 1.给一个可执行权限,在第一台realserver上运行-h,看帮助, 2.创建realserver :运行脚本输入realsever 3.创建lvs:运行脚本输入lvs #!/bin/bash#builed realserverrealserver() {    A=`cat /proc/sys/net/ipv4/conf/all/arp_ignore`    if [ $A -eq 0 ]; then        echo 1 > /proc

SQL语句技巧:查询存在一个表而不在另一个表中的数据记录

原文:SQL语句技巧:查询存在一个表而不在另一个表中的数据记录 方法一(仅适用单个字段)使用 not in ,容易理解,效率低 select A.ID from A where A.ID not in (select ID from B) 方法二(适用多个字段匹配)使用 left join...on... , "B.ID isnull" 表示左连接之后在B.ID 字段为 null的记录 select A.ID from A left join B on A.ID=B.ID where