Python 订单号生成方案(高并发 根据java源码重写)

# -*- coding: utf-8 -*-
# 时间工具
import time
import numpy as nu
import util


class Date(object):
    """
    日期对象
    """

    __seconds = 0

    def __init__(self, seconds=None):
        """
        初始化时间对象
        :param seconds: 时间戳秒
        """
        self.setTime(seconds)

    def setTime(self, seconds=None):
        """
        设置时间戳
        :param seconds:
        :return:
        """
        if seconds is None:
            seconds = self.now()
        self.__seconds = seconds

    def timeFormat(self, format='%Y-%m-%d %H:%M:%S', seconds=None):
        """
        时间格式化
        :param format: 格式化方案
        :param seconds: 秒 如果不填则默认为当前对象秒
        :return:
        """
        seconds = self.__check_seconds(seconds)
        return time.strftime(format, time.localtime(seconds))

    def getSecond(self, seconds=None):
        """
        获取秒钟
        :param seconds:
        :return:
        """
        seconds = self.__check_seconds(seconds)
        return time.strftime('%S', time.localtime(seconds))

    def getSeparate(self, seconds=None):
        """
        获取分钟
        :param seconds:
        :return:
        """
        seconds = self.__check_seconds(seconds)
        return time.strftime('%M', time.localtime(seconds))

    def getHour(self, seconds=None):
        """
        获取小时
        :param seconds:
        :return:
        """
        seconds = self.__check_seconds(seconds)
        return time.strftime('%H', time.localtime(seconds))

    def getDay(self, seconds=None):
        """
        获取月中的日
        :param seconds:
        :return:
        """
        seconds = self.__check_seconds(seconds)
        return time.strftime('%d', time.localtime(seconds))

    def getMonth(self, seconds=None):
        """
        获取月
        :param seconds:
        :return:
        """
        seconds = self.__check_seconds(seconds)
        return time.strftime('%m', time.localtime(seconds))

    def getYear(self, seconds=None):
        """
        获取年
        :param seconds:
        :return:
        """
        seconds = self.__check_seconds(seconds)
        return time.strftime('%Y', time.localtime(seconds))

    def __check_seconds(self, seconds=None):
        """
        校验时间戳-秒 参数
        :param seconds:
        :return:
        """
        if seconds is None:
            if self.__seconds is None:
                seconds = self.now()
            else:
                seconds = self.__seconds
        return seconds

    @staticmethod
    def now(mode='s'):
        """
        获取时间戳方案
        :param mode: s 秒 ms 毫秒 ns 纳秒
        :return:
        """
        time_mode = nu.array(util.TimeMode)
        if not (time_mode == mode).any():
            mode = util.TimeMode[0]
        ns = str(time.time_ns())
        if mode == util.TimeMode[0]:
            return int(ns[:len(ns) - 9])
        if mode == util.TimeMode[1]:
            return int(ns[:len(ns) - 6])
        if mode == util.TimeMode[2]:
            return int(ns)
# -*- coding: utf-8 -*-
# 异常对象组


class AuthException(Exception):
    """
    自定义异常对象 - 带消息参数方案
    """
    def __init__(self, msg):
        self.msg = msg

    def __str__(self):
        return self.msg
# -*- coding: utf-8 -*-
# 随机工具
from exceptions import AuthException
from util.time_util import Date


class OrderNumber(object):
    """
    订单号生成对象
    """
    # 开始时间戳
    __twepoch = 1420041600000
    # 机器id所占的位数
    __worker_id_bits = 5
    # 数据标识id所占的位数
    __datacenter_id_bits = 5
    # 支持的最大机器id
    __max_worker_id = -1 ^ (-1 << __worker_id_bits)
    # 支持的最大标识id
    __max_datacenter_id = -1 ^ (-1 << __datacenter_id_bits)
    # 序列在id中占的位数
    __sequence_bits = 12
    # 机器id向左偏移位
    __worker_id_shift = __sequence_bits
    # 数据标识id向左偏移数
    __datacenter_id_shift = __sequence_bits + __worker_id_shift
    # 时间戳向左偏移数
    __timestamp_left_shift = __sequence_bits + __worker_id_bits + __datacenter_id_bits
    # 生成序列的掩码
    __sequence_mask = -1 ^ (-1 << __sequence_bits)
    # 当前工作的机器id
    __worker_id = 0
    # 毫秒内序列
    __datacenter_id = 0
    # 毫秒内序列
    __sequence = 0
    # 上一次生成id时的时间戳
    __last_timestamp = -1

    def __init__(self, worker_id=0, datacenter_id=0):
        """
        构造函数
        :param worker_id: 工作id
        :param datacenter_id: 数据中心id
        """
        if worker_id > self.__max_worker_id or worker_id < 0:
            raise AuthException("worker Id can't be greater than {} or less than 0".format(self.__max_worker_id))
        if datacenter_id > self.__max_datacenter_id or datacenter_id < 0:
            raise AuthException(
                "datacenter Id can't be greater than %d or less than 0".format(self.__max_datacenter_id))
        self.__worker_id = worker_id
        self.__datacenter_id = datacenter_id

    @staticmethod
    def __time_gen():
        """
        获取当前时间(毫秒级)
        :return:
        """
        return Date().now('ms')

    def __time_next_millis(self, last_timestamp: int):
        """
        阻塞到下一毫秒级,直到获取到新的时间戳
        :param last_timestamp: 上一次生成id的时间戳
        :return:
        """
        timestamp = self.__time_gen()
        while timestamp <= last_timestamp:
            timestamp = self.__time_gen()
        return timestamp

    def next_id(self):
        """
        获取下一个id
        :return:
        """
        timestamp = self.__time_gen()
        if timestamp < self.__last_timestamp:
            raise AuthException("Clock moved backwards.  Refusing to generate id for {} milliseconds".format(
                self.__last_timestamp - timestamp))
        if self.__last_timestamp == timestamp:
            self.__sequence = (self.__sequence + 1) & self.__sequence_mask
            if self.__sequence == 0:
                timestamp = self.__time_next_millis(self.__last_timestamp)
        else:
            self.__sequence = 0
        self.__last_timestamp = timestamp
        return ((timestamp - self.__twepoch) << self.__timestamp_left_shift) | (
                self.__datacenter_id << self.__datacenter_id_shift) | (
                       self.__worker_id << self.__worker_id_shift) | self.__sequence

# demo
# import util.random_util as ur
# import threading
#
#
# orders = []
# threads = []
#
#
# def for_run(worker_id=0, datacenter_id=0, thread_num=1):
#     order = ur.OrderNumber(worker_id, datacenter_id)
#     for i in range(0, 2000):
#         order_number = str(order.next_id())
#         orders.append(order_number)
#         print('进程{}: 生成的订单号为:'.format(str(thread_num)) + order_number)
#
#
# if __name__ == '__main__':
#     for j in range(0, 30):
#         t = threading.Thread(target=for_run, args=(j, 0, j))
#         threads.append(t)
#     for t in threads:
#         t.setDaemon(True)
#         t.start()
#     for t in threads:
#         t.join()
#     print(len(orders))
#     orders = list(set(orders))
#     print(len(orders))

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容