V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
ladypxy
V2EX  ›  Python

Python 求平均运行时间

  •  
  •   ladypxy · 2018-10-24 09:38:54 +08:00 · 3046 次点击
    这是一个创建于 2221 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如题,log 类似下面这样

    get_foo start 913912131
    get_foo end 14141251132
    get_abc start 12312415
    get_def start 123156151
    get_def end 123115112312
    get_abc end 121515161
    

    第一列是线程名,最后一列是线程运行时间 怎么求同名线程的平均运行时间?

    20 条回复    2018-10-24 18:26:58 +08:00
    laqow
        1
    laqow  
       2018-10-24 09:43:47 +08:00 via Android
    给个 lock 让主线程去算啊
    ladypxy
        2
    ladypxy  
    OP
       2018-10-24 09:46:08 +08:00 via iPhone
    @laqow python 练习题……就是分析日志
    holajamc
        3
    holajamc  
       2018-10-24 10:06:14 +08:00
    这……怎么平均
    ladypxy
        4
    ladypxy  
    OP
       2018-10-24 10:12:50 +08:00
    @holajamc 我的理解是,首先筛选第一列相同的 get_foo,然后就一行 end 的第三列减去一行 start 的第三列。就是一次执行时间,然后把文件中所有 get_foo 的执行时间求和,除以执行次数
    holajamc
        5
    holajamc  
       2018-10-24 10:35:04 +08:00
    @ladypxy 但是线程名都不相同…而且都只运行了一次 emmm 不懂
    msg7086
        6
    msg7086  
       2018-10-24 10:46:40 +08:00
    @holajamc 人家总不能贴个几万行的日志上论坛吧……
    ladypxy
        7
    ladypxy  
    OP
       2018-10-24 10:48:40 +08:00
    @holajamc 这只是日志格式。。。不能贴几百行上来啊。。难点就是线程名不同,要先根据线程名筛选,然后再根据 start end 筛选。
    我目前想法是,用多个 list 来实现,但是感觉太笨重了。。
    holajamc
        8
    holajamc  
       2018-10-24 10:55:27 +08:00
    @msg7086
    @ladypxy
    2333 确实有些误解了
    xcolder
        9
    xcolder  
       2018-10-24 11:01:15 +08:00
    塞到 map 里
    beny2mor
        10
    beny2mor  
       2018-10-24 11:01:20 +08:00
    用一个 namedtuple 和一个 dict 就可以了吧
    统计值放到 tuple namedtuple('LogStatistic', ['已经统计的线程数', '统计过的线程的时间'])

    用一个 dict 保存线程的开始时间 {'get_foo': {start: 913912131}, 'get_abc': {start: 12312415}} 用来保存时间,每读取到数据看看是否 start 和 end 都有了,有的话从 dict 中删除这个键,统计进入 tuple
    princelai
        11
    princelai  
       2018-10-24 11:15:29 +08:00
    用到了 python pandas 包

    df = pd.read_clipboard(header=None)

    df.columns = ['process','status','time']

    df.groupby(by='process').apply(lambda x:(x.sort_values(by='time').loc[x.status=='end','time'].values - - x.sort_values(by='time').loc[x.status=='start','time'].values).mean())


    前提是要保证线程的 start 和 end 的数量是匹配的

    写完上面我又想到一个更好的办法,透视表
    df_pivot = df.pivot_table( values='time', index='process',columns='status',aggfunc=list)

    df_pivot.apply(lambda x:(pd.np.array(sorted(x.end)) - pd.np.array(sorted(x.start))).mean(), axis=1)
    xpresslink
        12
    xpresslink  
       2018-10-24 11:45:08 +08:00
    首先楼主的问题没有描述清楚,给的信息不够,如同名线程中后面的线程比前面的先结束,如何正确配对开始和结束时间?
    另外,说心理话这么简单个问题都要到这里来问,劝退。楼主你不是干这行的料。
    ladypxy
        13
    ladypxy  
    OP
       2018-10-24 12:10:57 +08:00
    @princelai 用 pandas 实现很简单,但是最好使用自带的函数解决。。。下面的不错,不过我 pivot 一点没看。。。但是表示感谢。。。。

    @xpresslink 原始的题目就是这样的,应该是同名的前面的总是比后面的先结束。
    我本来就不是码农,闲的没事学 python,我这才看了 3 天,有问题还不能问了? 看了下你的回帖,总是对提问人各种嘲讽。难道你是什么都知道?呵呵
    princelai
        14
    princelai  
       2018-10-24 14:21:03 +08:00 via Android
    @ladypxy 那也简单啊,建个 defaultdict ( list ),key 是( process,status ),value 是[time],然后相减,其实就是一个 group by 操作
    xpresslink
        15
    xpresslink  
       2018-10-24 14:24:37 +08:00
    @ladypxy,我这么说你肯定不服气,下面用你能理解的方式写了一个算法。

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-

    data = """get_foo start 913912131
    get_foo end 14141251132
    get_abc start 12312415
    get_def start 123156151
    get_def end 123115112312
    get_abc end 121515161
    get_foo start 913912131
    get_foo end 14141251132
    get_abc start 12312415
    get_def start 123156151
    get_def end 123115112312
    get_abc end 121515161
    get_foo start 913912131
    get_foo end 14141251132
    get_abc start 12312415
    get_def start 123156151
    get_def end 123115112312
    get_abc end 121515161
    """

    i_data = (l.split() for l in data.splitlines())

    result={}
    for proc, flag, timestamp in i_data:
    □□□□temp = result.setdefault(proc, {'sum':0,'cnt':0, 'start':0})
    □□□□if flag == 'start':
    □□□□□□□□temp['start']=int(timestamp)
    □□□□else:
    □□□□□□□□temp['sum'] += int(timestamp) - temp['start']
    □□□□□□□□temp['cnt'] += 1

    for p, v in result.items():
    □□□□print('process:', p, 'avg time:',v['sum']/v['cnt'])
    jmc891205
        16
    jmc891205  
       2018-10-24 14:31:09 +08:00
    最暴力的做法
    线程名做 key,总时间和运行次数组成一个 tuple 做 value
    遍历一遍日志全塞到一个 dict 里
    最后遍历一遍 dict 把每个线程的平均时间求出来
    ladypxy
        17
    ladypxy  
    OP
       2018-10-24 14:57:20 +08:00
    用比较笨的方法实现了一下

    with open('logtest.txt','r',encoding='utf-8') as f:
    list=[]
    for lines in f:
    list.append(lines.split())

    api_name={}
    count={}
    for i in list:
    if i[0] not in api_name:
    api_name.update({i[0]:(0-int(i[2]))})
    count.update({i[0]:int("1")})
    else:
    if i[1] =="end":
    api_name.update({i[0]:(int(i[2])+int(api_name[i[0]]))})
    count.update({i[0]:(count[i[0]]+1)})
    if i[1] == "start":
    api_name.update({i[0]:(int(api_name[i[0]]-int(i[2])))})
    count.update({i[0]:(count[i[0]]+1)})

    for i in count.keys():
    print('api',i,"average running time =",api_name[i] / count[i])
    aijam
        18
    aijam  
       2018-10-24 16:55:30 +08:00
    import sys

    d = {}
    n = 0
    s = 0
    for line in sys.stdin:
    ____name, flag, t = line.split()
    ____t = int(t)
    ____if flag == "start":
    ________d[name] = t
    ____elif name in d:
    ________s += t - d[name]
    ________n += 1
    ________del d[name]

    print(s / n)
    shm7
        19
    shm7  
       2018-10-24 17:05:05 +08:00
    导入 pandas,求出 unique names,然后 reshape(2, N/2), sum(ax=1) -> (start_sum, end_sum) -> (end_sum - start_sum) / N * 2
    ladypxy
        20
    ladypxy  
    OP
       2018-10-24 18:26:58 +08:00
    @aijam 感谢回复。。。第一次发现 python 居然可以这样赋值。。name, flag, t = line.split()
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5322 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 50ms · UTC 08:30 · PVG 16:30 · LAX 00:30 · JFK 03:30
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.