Giter VIP home page Giter VIP logo

Comments (6)

Choumiko avatar Choumiko commented on July 26, 2024

That's difficult to measure i think since in the case of table.each you're mostly trying to meassure the cost of 1 function call (+1 if statement and passing varargs). I think it's more benefical if one tries to follow broader optimisations, like e.g. here: https://springrts.com/wiki/Lua_Performance#TEST_9:_for-loops
I've run some speed tests involving stdlib before, where i applied some of these: #59

What concerns me most in the code you linked is the fact that it's titled avoiding iteration but actually the improved code ends up (mostly) doubling the iterations without it being obvious (table.filter and table.each both iterate over a possibly large table). Guess something like table.each_filtered() would be handy.

from factorio-stdlib.

Xuerian avatar Xuerian commented on July 26, 2024

The page you link says this:

Don't use pairs() or ipairs() in critical code! Try to save the table-size somewhere and use for i=1,x do!

Using a fori loop when possible (Which can include keeping two arrays instead of a hash table, and doing the fori that way) is a pretty clear gain in critical code.

I'm all for using the functional approach when it's not a critical path, but the evidence is pretty clear that even the overhead of using pairs/ipairs is big, not counting having the user abstract the body of the loop into yet another call.

Really it seems like I'm trying to make a big deal out of it, but even just putting a link to the page you linked here below that section in the docs it is the kind of thing I'm suggesting.

from factorio-stdlib.

Afforess avatar Afforess commented on July 26, 2024

I've delayed responding not because I didn't notice the issue but because I wanted to think about reply a bit.

The core complaint you've raised is that functions / iterations can be expensive, and stdlib recommends practices which may exacerbate this problem. I think this is an entirely fair criticism. The standard library is first and foremost concerned with encouraging quality code, precision, and utility. I think if we ever reach the day where many modders, having adopted the stdlib, find that certain stdlib recommendations hurt their performance, then I will be happy in succeeding in my earlier goals and having found a new challenge to face.

In regards to @Choumiko I think what you are noticing is that the stdlib table functions are all independent operators, unaware of the existence of iteration. What you are really asking for is a set of functions around iteration. For example, consider the example from the wiki:

require 'stdlib/table'
require 'stdlib/game'
require 'stdlib/event/event'
require 'stdlib/area/position'

Event.register(defines.events.on_player_created, function(event)
    local player = game.players[event.player_index].character
    local force = player.force
    local valid_enemies = table.filter(player.surface.find_entities_filtered(area = Position.expand_to_area(player.position, 25), type = 'unit', force = 'enemy'}), Game.VALID_FILTER)
    table.each(valid_enemies, function(entity)
         entity.damage(100, force)
    end)
end)

You're right, it does iterate the list of biters twice. If there were an iterator API, it might look like this:

require 'stdlib/iterator'
require 'stdlib/game'
require 'stdlib/event/event'
require 'stdlib/area/position'

Event.register(defines.events.on_player_created, function(event)
    local player = game.players[event.player_index].character
    local force = player.force
    local iter = iterator.new(player.surface.find_entities_filtered(area = Position.expand_to_area(player.position, 25), type = 'unit', force = 'enemy'}))
    iter:filter(Game.VALID_FILTER)
    iter:each(function(entity) entity.damage(100, force) end)
    iter:apply()
end)

iterator.new would create an iterator object, holding an array of objects. Then, filter/each/mapping operations could be added to the iterator, but adding these would not cause the iterator to execute until iterator.apply was called. So in this example, the iteration stream was given the list of biters, then told how to filter it, and then told to execute a function for each, and then told to execute all the operations in order. This stream of operations would only result in iterating the initial list once, satisfying your performance concerns. Other languages have this sort of API (Ruby Blocks, Python Generators, Java Streams, etc), and there is no reason it can't be given to lua as well. (Actually, Lua has coroutines but the API for coroutines is so obtuse as to be unreadable.)

from factorio-stdlib.

Xuerian avatar Xuerian commented on July 26, 2024

The core complaint you've raised is that functions / iterations can be expensive, and stdlib recommends practices which may exacerbate this problem.

I didn't mean to come across as complaining about it, I was just hoping to make sure users are aware of potential pitfalls to the mostly-preferable stdlib approach if they're either iterating large sets of data or at a high frequencies, which is certainly not going to be the case most of the time. @Choumiko's link seems pretty good, but even then you're likely right and it's unlikely to be the issue.

I think if we ever reach the day where many modders, having adopted the stdlib, find that certain stdlib recommendations hurt their performance, then I will be happy in succeeding in my earlier goals and having found a new challenge to face.

Hah, that's fair.

from factorio-stdlib.

Afforess avatar Afforess commented on July 26, 2024

Retitled with @Xuerian's approval.

from factorio-stdlib.

Afforess avatar Afforess commented on July 26, 2024

I wrote an early proof-of-concept but its performance is actually worse than straight tables (see the busted tests for a benchmark) and won't make the cut as is.

https://github.com/Afforess/Factorio-Stdlib/blob/95bf8434f7b6a13c40ce3196eda3034b0977ef64/stdlib/iterator.lua

from factorio-stdlib.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.