如何在芹菜任务中调用python 3.5异步函数?

时间:2018-05-24 11:47:49

标签: python asynchronous celery

我在python 3.5中有一个异步函数,如下所示:

tawkchat-minified-box

和一个芹菜定期任务调用异步get_pool()函数,它对它的数据执行操作:

async def get_pool():
    if Cache.__current:
        return Cache.__current

    Cache.__current = await aioredis.create_redis_pool(
        (settings.CACHE_SETTINGS['SERVER'], settings.CACHE_SETTINGS['PORT']),
        minsize=settings.CACHE_SETTINGS['MIN_SIZE'],
        maxsize=settings.CACHE_SETTINGS['MAX_SIZE'])

    return Cache.__current

符合预期此代码会出错:

@app.task
def check_data_task():
    cache = Cache.get_pool()
    ...

现在是时候提问了:

  1. 这是一个在celery任务中使用python异步函数的好主意吗?如果是的话:
  2. 如何在芹菜任务中使用python coroutine函数?

1 个答案:

答案 0 :(得分:0)

struct Grid
{
    enum Layout {
        case fixedCellSize(CGSize)
        case dimensions(rowCount: Int, columnCount: Int)
        case aspectRatio(CGFloat)
    }

    var layout: Layout { didSet { recalculate() } }

    var frame: CGRect { didSet { recalculate() } }

    init(layout: Layout, frame: CGRect = CGRect.zero) {
        self.frame = frame
        self.layout = layout
        recalculate()
    }

    subscript(row: Int, column: Int) -> CGRect? {
        return self[row * dimensions.columnCount + column]
    }

    subscript(index: Int) -> CGRect? {
        return index < cellFrames.count ? cellFrames[index] : nil
    }

    var cellCount: Int {
        get {
            switch layout {
            case .aspectRatio: return cellCountForAspectRatioLayout
            case .fixedCellSize, .dimensions: return calculatedDimensions.rowCount * calculatedDimensions.columnCount
            }
        }
        set { cellCountForAspectRatioLayout = newValue }
    }

    //Contains the size of the cells (which are all equal in size).
    var cellSize: CGSize {
        get { return cellFrames.first?.size ?? CGSize.zero }
        set { layout = .fixedCellSize(newValue) }
    }

    //Contains the number of rows and columns that will be used.
    var dimensions: (rowCount: Int, columnCount: Int) {
        get { return calculatedDimensions }
        set { layout = .dimensions(rowCount: newValue.rowCount, columnCount: newValue.columnCount) }
    }

    var aspectRatio: CGFloat {
        get {
            switch layout {
            case .aspectRatio(let aspectRatio):
                return aspectRatio
            case .fixedCellSize(let size):
                return size.height > 0 ? size.width / size.height : 0.0
            case .dimensions(let rowCount, let columnCount):
                if rowCount > 0 && columnCount > 0 && frame.size.width > 0 {
                    return (frame.size.width / CGFloat(columnCount)) / (frame.size.width / CGFloat(rowCount))
                } else {
                    return 0.0
                }
            }
        }
        set { layout = .aspectRatio(newValue) }
    }

    private var cellFrames = [CGRect]()
    private var cellCountForAspectRatioLayout = 0 { didSet { recalculate() } }
    //This 0, 0 value will be updated after initialization
    private var calculatedDimensions: (rowCount: Int, columnCount: Int) = (0, 0)

    private mutating func recalculate() {
        switch layout {
        case .fixedCellSize(let cellSize):
            //Unlike .dimensions, here there should be some spacing unless height and width were already ints.
            if cellSize.width > 0 && cellSize.height > 0 {
                calculatedDimensions.rowCount = Int(frame.size.height / cellSize.height)
                calculatedDimensions.columnCount = Int(frame.size.width / cellSize.width)
                updateCellFrames(to: cellSize)
            } else {
                assert(false, "Grid: for fixedCellSize layout, cellSize height and width must be positive numbers")
                calculatedDimensions = (0, 0)
                cellFrames.removeAll()
            }
            //Still checking why, down here, it calculates the cellSize as exactly fitting in frame/rows or columns. Then the spacing there would be 0...
        case .dimensions(let rowCount, let columnCount):
            if columnCount > 0 && rowCount > 0 {
                calculatedDimensions.rowCount = rowCount
                calculatedDimensions.columnCount = columnCount
                let cellSize = CGSize(width: frame.size.width/CGFloat(columnCount), height: frame.size.height/CGFloat(rowCount))
                updateCellFrames(to: cellSize)
            } else {
                assert(false, "Grid: for dimensions layout, rowCount and columnCount must be positive numbers")
                calculatedDimensions = (0, 0)
                cellFrames.removeAll()
            }
        case .aspectRatio:
            assert(aspectRatio > 0, "Grid: for aspectRatio layout, aspectRatio must be a positive number")
            let cellSize = largestCellSizeThatFitsAspectRatio()
            if cellSize.area > 0 {
                calculatedDimensions.columnCount = Int(frame.size.width / cellSize.width)
                calculatedDimensions.rowCount = (cellCount + calculatedDimensions.columnCount - 1) / calculatedDimensions.columnCount
            } else {
                calculatedDimensions = (0, 0)
            }
            updateCellFrames(to: cellSize)
            break
        }
    }


    private mutating func updateCellFrames(to cellSize: CGSize) {
        cellFrames.removeAll()

        //Checks the size in width and height that the amounts of cells will take.
        let boundingSize = CGSize(
            width: CGFloat(dimensions.columnCount) * cellSize.width,
            height: CGFloat(dimensions.rowCount) * cellSize.height
        )
        //That information is then used to determine the spacing from the beginning and end of the axis, and between the cells themselves. SHOULDN'T THIS BE ZERO THOUGH, AS cellSize TOOK THE MAX POSSIBLE SIZE TO FILL THE FRAME?
        let offset = (
            dx: (frame.size.width - boundingSize.width) / 2,
            dy: (frame.size.height - boundingSize.height) / 2
        )

        var origin = frame.origin
        origin.x += offset.dx
        origin.y += offset.dy

        //Puts every cell in the cellFrames array, with their corresponding CGRect values.
        if cellCount > 0 {
            for _ in 0..<cellCount {
               cellFrames.append(CGRect(origin: origin, size: cellSize))
                origin.x += cellSize.width
                if round(origin.x) > round(frame.maxX - cellSize.width) {
                    origin.x = frame.origin.x + offset.dx
                    origin.y += cellSize.height
                }
            }
        }
    }

    private func largestCellSizeThatFitsAspectRatio() -> CGSize {
        var largestSoFar = CGSize.zero
        if cellCount > 0 && aspectRatio > 0 {
            for rowCount in 1...cellCount {
                largestSoFar = cellSizeAssuming(rowCount: rowCount, minimumAllowedSize: largestSoFar)
            }
            for columnCount in 1...cellCount {
                largestSoFar = cellSizeAssuming(columnCount: columnCount, minimumAllowedSize: largestSoFar)
            }
        }
        return largestSoFar
    }

    private func cellSizeAssuming(rowCount: Int? = nil, columnCount: Int? = nil, minimumAllowedSize: CGSize = CGSize.zero) -> CGSize {
        var size = CGSize.zero
        if let columnCount = columnCount {
            size.width = frame.size.width / CGFloat(columnCount)
            size.height = size.width / aspectRatio
        } else if let rowCount = rowCount {
            size.height = frame.size.height / CGFloat(rowCount)
            size.width = size.height * aspectRatio
        }
        if size.area > minimumAllowedSize.area {
            if Int(frame.size.height / size.height) * Int(frame.size.width / size.width) >= cellCount {
                return size
            }
        }
        return minimumAllowedSize
    }
}

private extension CGSize {
    var area: CGFloat {
        return width * height
    }
}